Java高级之泛型、自定义泛型、通配符的使用
泛型与File
文章目录
- 一、为什么要有泛型?
- 1.1、什么是泛型?
- 1.2、泛型的设计背景
- 1.3、泛型的概念
- 二、在集合中使用泛型
- 三、自定义泛型结构
- 2.1、泛型方法的使用
- 四、泛型在继承上的体现
- 五、通配符的使用
- 5.1、通配符的使用
- 5.2、有限制条件的通配符的使用
- 六、泛型应用举例
一、为什么要有泛型?
jdk5.0新增的特性
1.1、什么是泛型?
泛型:标签;Generic
举例:
- 中药店:每个抽屉外面贴着标签
- 超市购物架上很多瓶子,每个瓶子装的是什么,有标签
1.2、泛型的设计背景
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的 对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于 这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就 是类型参数,即泛型。
1.3、泛型的概念
所谓泛型,就是允许在定义类、接口时通过一个标识类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)
二、在集合中使用泛型
在集合中使用泛型:
总结:
-
集合接口或集合类在jdk5.0时都修改为带泛型的结构。
-
在实例化集合类时,可以指明具体的泛型结构
-
指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用
比如:add(E e) —> 实例化以后:add(Integer e)
-
注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
-
如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
举例1:
/*** 在集合中使用泛型的情况::以 HashMap 为例*/
@Test
public void test3(){HashMap<String, Integer> map = new HashMap<>();map.put("Jack", 123);map.put("Tom", 156);map.put("Book", 189);map.put("Abby", 145);Set<Map.Entry<String, Integer>> entry = map.entrySet();Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();while (iterator.hasNext()){Map.Entry<String, Integer> entry1 = iterator.next();String key = entry1.getKey();Integer value = entry1.getValue();System.out.println(key + "-->" + value);}
}
举例2:
/*** 在集合中使用泛型的情况:以 ArrayList为例*/@Testpublic void test2(){ArrayList<Integer> list = new ArrayList<Integer>();//存放学生的成绩list.add(78);list.add(66);list.add(98);list.add(80);//遍历方式二:包装类,使用增强for循环
// for (Integer score: list){
// int stuScore = score;
// //避免强转
// System.out.println(stuScore);
// }//遍历方式三:迭代器的方式Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}// 遍历方式一:转为数组
// System.out.println(Arrays.toString(list.toArray()));//问题一:类型不安全
// list.add("Tom");
// for (Object score:list){
// //强转,可能出现 ClassCastException
// int stuScore = (Integer) score;
// System.out.println(stuScore);
// }}
三、自定义泛型结构
如何自定义泛型结构:泛型类、泛型接口,泛型方法
自定义泛型类 Order
import java.util.ArrayList;
import java.util.List;/*** @author: Arbicoral* @Description: 自定义的泛型类*/
public class Order<T> {String name;int orderId;/*** ① 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系* 下面例子中:类的泛型是 String ,泛型方法的泛型是 Integer,没有任何关系* ② 换句话说,泛型方法所属的类是不是泛型类都没有关系* ③ 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化时确定的*/public static <E> List<E> copyFromArrayList(E[] arr){ArrayList<E> list = new ArrayList<>();for (E e: arr){list.add(e);}return list;}//类的内部结构就可以使用类的泛型T orderT;public Order(){//编译不通过:此时T还是变量,只是变量是用类型来充当的//T[] arr = new T[10];//强转,编译通过T[] arr = (T[]) new Object[10];};public Order(String name, int orderId, T orderT){this.orderT = orderT;this.orderId = orderId;this.name = name;}public T getOrderT() {return orderT;}public void setOrderT(T orderT){this.orderT = orderT;}@Overridepublic String toString() {return "Order{" +"name='" + name + '\'' +", orderId=" + orderId +", orderT=" + orderT +'}';}// /**
// * 静态方法中不能使用类的泛型
// * 因为类的泛型是造对象的时候确定的,静态方法早于对象创建的,相当于类型还没有确定就要用了,不行!
// * @param orderT
// */
// public static void show(T orderT){
// System.out.println(orderT);
// }// public void show(){
// //编译不通过
// try{
//
// }catch (T t)
// }
}
Order的2个子类SubOrder、SubOrder1
public class SubOrder extends Order<Integer>{//SubOder:不再是泛型类
}
public class SubOder1<T> extends Order<T>{//SubOder1<T>:仍然是泛型类
}
注意点:
泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:
<E1, E2, E3>
泛型类的构造器如下:public GenericClass(){}。
而下面是错误的:public GenericClass<\E>(){}
实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
泛型不同的引用不能相互赋值。 >尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有 一个ArrayList被加载到JVM中。
泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价 于Object。经验:泛型要使用一路都用。要不用,一路都不要用。
如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
jdk1.7,泛型的简化操作:ArrayList flist = new ArrayList<>();
泛型的指定中不能使用基本数据类型,可以使用包装类替换。
在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法 中不能使用类的泛型。
异常类不能是泛型的
不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]; 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。
父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型
子类不保留父类的泛型:按需实现
- 没有类型 擦除
- 具体类型
子类保留父类的泛型:泛型子类
全部保留
部分保留
结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自 己的泛型
/*** 注意点4:泛型不同的引用不能相互赋值。*/
public void test3(){ArrayList<String> list1 = null;ArrayList<Integer> list2 = null;//泛型不同的引用不能相互赋值。//list2 = list1;
}
/*** @author: Arbicoral* @Description: 注意点10: 异常类不能声明为泛型类*/
public class MyException<T> extends Exception {
}
2.1、泛型方法的使用
@Test
/*** ① 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系* 下面例子中:类的泛型是 String ,泛型方法的泛型是 Integer,没有任何关系* ② 换句话说,泛型方法所属的类是不是泛型类都没有关系* ③ 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化时确定的*/
public void test4(){Order<String> order = new Order<>();Integer[] arr = new Integer[]{1,2,3,4};//泛型方法在调用时,指明泛型参数的类型List<Integer> list = order.copyFromArrayList(arr);System.out.println(list);
}
四、泛型在继承上的体现
/*** 1. 泛型在继承方面的体现* 虽然类A 是类B的父类, 但是G<A> 和 G<B>二者不具备子父类关系,二者是并列关系** 补充:类A 是类B的父类, A<G> 是B<G>的父类*/
@Test
public void test1(){Object obj = null;String str = null;//多态obj = str;Object[] arr1 = null;String[] arr2 = null;//多态展示arr1 = arr2;List<Object> list1 = null;List<String> list2 = null;//此时的list1 和 list2 的类型不具有子父类关系//编译不通过// list1 = list2;
}
五、通配符的使用
5.1、通配符的使用
/*** 2. 通配符的使用* 通配符:?* 类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是G<?>*/
@Test
public void test2(){List<Object> list1 = null;List<String> list2 = null;List<?> list = null;list = list1;list = list2;print(list1);print(list2);
}//遍历
public void print(List<?> list){Iterator<?> iterator = list.iterator();while (iterator.hasNext()){Object next = iterator.next();System.out.println(next);}
}
5.2、有限制条件的通配符的使用
六、泛型应用举例
定义一个泛型类 DAO,在其中定义一个 Map 成员变量,Map 的键 为 String 类型,值为 T 类型。
分别创建以下方法:
- public void save(String id,T entity): 保存 T 类型的对象到 Map 成员 变量中
- public T get(String id):从 map 中获取 id 对应的对象
- public void update(String id,T entity):替换 map 中 key 为 id 的内容, 改为 entity 对象
- public List list():返回 map 中存放的所有 T 对象
- public void delete(String id):删除指定 id 对象
定义一个 User 类: 该类包含:private 成员变量(int 类型) id,age;(String 类型)name。
定义一个测试类: 创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方 法来操作 User 对象, 使用 Junit 单元测试类进行测试
泛型类 DAO
package 20230527.exer;import java.util.*;/*** @author: Arbicoral* @create: 2023-05-27 17:45* @Description:** 定义个泛型类 DAO<T>,在其中定义一个 Map 成员变量,Map 的键为 String 类型,值为 T 类型。* 分别创建以下方法:* public void save(String id,T entity): 保存 T 类型的对象到 Map 成员变量中* public T get(String id):从 map 中获取 id 对应的对象* public void update(String id,T entity):替换 map 中 key 为 id 的内容,改为 entity 对象* public List<T> list():返回 map 中存放的所有 T 对象* public void delete(String id):删除指定 id 对象*/
public class DAO<T> {private Map<String, T> map = new HashMap<String, T>();/*** 保存 T 类型的对象到 Map 成员变量中* @param id* @param entity*/public void save(String id,T entity){map.put(id, entity);}/*** 从 map 中获取 id 对应的对象*/public T get(String id){return map.get(id);}/*** 替换 map 中 key 为 id 的内容,改为 entity 对象*/public void update(String id,T entity){if (map.containsKey(id)){map.put(id, entity);}}/*** 返回 map 中存放的所有 T 对象* @return*/public List<T> list(){//错误的
// Collection<T> values = map.values();
// return (List<T>) values;//正确的ArrayList<T> list = new ArrayList<>();Collection<T> values = map.values();for(T t: values){list.add(t);}return list;}/**删除指定 id 对象*/public void delete(String id){map.remove(id);}
}
User 类
package 20230527.exer;
import java.util.Objects;/*** @author: Arbicoral* @create: 2023-05-27 20:16* @Description:** 定义一个 User 类:* 该类包含:private 成员变量(int 类型) id,age;(String 类型)name。*/
public class User {private int id;private int age;private String name;//空参构造器public User(){}//带参构造器public User(int id, int age, String name){this.age = age;this.id = id;this.name = name;}public void setId(int id){this.id = id;}public void setAge(int age) {this.age = age;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public int getId() {return id;}public String getName() {return name;}@Overridepublic String toString( ) {return "User{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return id == user.id && age == user.age && Objects.equals(name, user.name);}@Overridepublic int hashCode() {return Objects.hash(id, age, name);}
}
测试类
package 20230527.exer;import java.util.List;/*** @author: Arbicoral* @create: 2023-05-27 20:22* @Description:** 定义一个测试类:* 创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方法来操作 User 对象,* 使用 Junit 单元测试类进行测试*/
public class DAOTest {public static void main(String[] args) {DAO<User> dao = new DAO<User>();dao.save("1001", new User(1001, 34,"周杰伦"));dao.save("1002", new User(1002, 20,"昆凌"));dao.save("1003", new User(1003, 25,"蔡依林"));dao.update("1003", new User(1003, 35,"方文山"));dao.delete("1002");List<User> list = dao.list();list.forEach(System.out::println);}
}
相关文章:

Java高级之泛型、自定义泛型、通配符的使用
泛型与File 文章目录 一、为什么要有泛型?1.1、什么是泛型?1.2、泛型的设计背景1.3、泛型的概念 二、在集合中使用泛型三、自定义泛型结构2.1、泛型方法的使用 四、泛型在继承上的体现五、通配符的使用5.1、通配符的使用5.2、有限制条件的通配符的使用 …...
代码随想录二刷day32
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣122. 买卖股票的最佳时机 II二、力扣55. 跳跃游戏三、力扣45. 跳跃游戏 II 前言 一、力扣122. 买卖股票的最佳时机 II class Solution {public int ma…...
linux基础篇
文章目录 linux基础篇1.Linux文件系统结构:2.常用的Linux指令:3.Shell指令:4.Linux服务管理:5.Linux磁盘挂载:其他 linux基础篇 1.Linux文件系统结构: 根目录 /bin目录:二进制可执行文件存放处boot目录:启…...

文心一言插件开发全流程,ERNIE-Bot-SDK可以调用文心一言的能力
文心一言插件开发 前言插件插件是什么工作原理申请开发权限 开始第一步:安装python第二步:搭建项目manifest 描述文件:ai-plugin.json插件服务描述文件:openapi.yaml开发自己的plugin-server 第三步:上传插件 SDK相关链…...

Keepalived+LVS负载均衡
Keepalived 是一个用于实现高可用性的开源软件,它基于 VRRP(Virtual Router Redundancy Protocol)协议,允许多台服务器协同工作,以确保在某个服务器出现故障时服务的连续性。Keepalived 的核心思想是将多台服务器配置成…...

接口测试学习
1、curl 命令 无参:curl -X POST -H"Authorization: abcdefghijklmn" https://xxx.xxxxx.com/xxxx 有参:curl -X POST -H"Authorization:abcdefghijklmn " -H"Content-Type:application/json" https://xxx.xxxxx.com/…...

怎么用外网访问自己的网站?快解析内网端口映射来实现
想要访问服务器上的网站需要直接或间接访问服务器IP地址,但是如果服务器没有公网IP地址,那么就需要借助外网进行访问。当我们需要远程访问内网的Web服务器时,我们需要使用一些技术来实现此目的。这就需要通过使用类似快解析内网端口映射方式进…...

zabbix学习1--zabbix6.x单机
文章目录 1. 环境2. MYSQL8.02.1 单节点2.2 配置主从 3. 依赖组件4. zabbix-server5. agent5.1 yum5.2 编译 附录my.cnfJDK默认端口号 1. 环境 进入官网查看所需部署环境配置以及应用版本要求https://www.zabbix.com/documentation/current/zh/manual/installation/requiremen…...
Flink 的 Kafka Table API Connector
Flink datastream connectors 和 Flink table api connectors 的区别: Flink DataStream Connectors和Table API Connectors是Flink中用于连接外部数据源的两种不同的连接器。 1. Flink DataStream Connectors: - Flink DataStream Connectors是用于将外部数据源连…...
tcpdump 命令
一、TCPDUMP指定IP 在网络流量分析过程中,我们经常需要对指定的IP进行抓取和分析。使用TCPDUMP指定IP非常简单,只需要通过命令行参数-i指定需要抓取的网卡,并使用host参数指定目标IP地址即可:tcpdump -i eth0 host 192.168.0.1 上…...
哪些测试项目可以使用自动化测试?
通常,软件测试v的测试方式分为人工测试和自动化测试,人工测试是由测试人员编写并执行测试用例,然后观察测试结果与预期结果是否一致的过程;自动化测试是通过测试工具来代替或辅助人工去验证系统功能是否有问题的过程。 采用自动化测试需要满…...

【八大经典排序算法】冒泡排序
【八大经典排序算法】冒泡排序 一、概述二、思路解读三、代码实现四、优化 一、概述 冒泡排序由于其简单和易于理解,使其成为初学者学习排序算法的首选,也是初学者接触到的第一个排序算法。其原理是通过重复交换相邻的元素来将最大的元素逐步“冒泡”到…...

【IEEE会议】第五届机器人、智能控制与人工智能国际学术会议(RICAI 2023)
【IEEE列表会议】第五届机器人、智能控制与人工智能国际学术会议(RICAI 2023) 2023 5th International Conference on Robotics, Intelligent Control and Artificial Intelligence 第五届机器人、智能控制与人工智能国际学术会议(RICAI 20…...

如何在本地 Linux 主机上实现 Yearning SQL 审核平台的远程访问?
文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具,为DBA与开发人员使用…...
android.support.multidex.MultiDexApplication:DexPathList
修改项目的build.gradle文件,使用multidex并添加multidex库作为依赖,如下所示: android { defaultConfig { ... minSdkVersion 21 targetSdkVersion 28 multiDexEnabled true } ... } dependencies { compile com.android.support:multidex…...

云HIS医院信息化系统:集团化管理,多租户机制,满足医院业务需求
随着云计算、大数据、物联网等新兴技术的迅猛发展,HIS模式的理念、运行机制更新,衍生出了新的HIS模式——云HIS。云HIS是基于云计算、大数据、互联网等高新技术研发的医疗卫生信息平台,它实现了医院信息化从局域网向互联网转型,并…...
Docker拉取nginx镜像,部署若依Vue前端
前言 本文主要用来描述,如何用nginx部署若依项目的前端。 一、Docker 拉取 Nginx镜像 命令:docker pull nginx 二、Vue项目打包 2.1 先配置线上后端路径 说明:由于我打包命令是 npm run build:stage ,所以项目生效的环境文…...

简单介绍神经网络中不同优化器的数学原理及使用特性【含规律总结】
当涉及到优化器时,我们通常是在解决一个参数优化问题,也就是寻找能够使损失函数最小化的一组参数。当我们在无脑用adam时,有没有斟酌过用这个是否合适,或者说凭经验能够有目的性换用不同的优化器?是否用其他的优化器可…...

JL653—一个基于ARINC653的应用程序仿真调试工具
JL653是安装在PC机Windows操作系统上面的一层接插件,它能够真实地模拟ARINC653标准规定的功能性行为,从而可以供研发人员在PC机Windows环境下高效、快速的进行基于ARINC653的应用程序的开发、调试等。 JL653提供了ARINC 653 Part 1中要求的以下服务&…...

MQTT Paho Android 支持SSL/TLS(亲测有效)
MQTT Paho Android 支持SSL/TLS(亲测有效) 登录时支持ssl的交互 这是调测登录界面设计 代码中对ssl/tls的支持 使用MqttAndroidClient配置mqtt客户端请求时,不加密及加密方式连接存在以下几点差异: url及端口差异 val uri: String if (tlsConnect…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...