当前位置:首页 > 编程笔记 > 正文
已解决

Java高级之泛型、自定义泛型、通配符的使用

来自网友在路上 181881提问 提问时间:2023-09-18 22:44:38阅读次数: 81

最佳答案 问答题库818位专家为你答疑解惑

泛型与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、泛型的概念

所谓泛型,就是允许在定义类、接口时通过一个标识类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)

二、在集合中使用泛型

在集合中使用泛型:

总结:

  1. 集合接口或集合类在jdk5.0时都修改为带泛型的结构。

  2. 在实例化集合类时,可以指明具体的泛型结构

  3. 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用

    比如:add(E e) —> 实例化以后:add(Integer e)

  4. 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换

  5. 如果实例化时,没有指明泛型的类型。默认类型为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>:仍然是泛型类
}

注意点

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:

    <E1, E2, E3>

  2. 泛型类的构造器如下:public GenericClass(){}。

    ​ 而下面是错误的:public GenericClass<\E>(){}

  3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。

  4. 泛型不同的引用不能相互赋值。 >尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有 一个ArrayList被加载到JVM中。

  5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价 于Object。经验:泛型要使用一路都用。要不用,一路都不要用。

  6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。

  7. jdk1.7,泛型的简化操作:ArrayList flist = new ArrayList<>();

  8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。

  9. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法 中不能使用类的泛型。

  10. 异常类不能是泛型的

  11. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]; 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。

  12. 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型

    • 子类不保留父类的泛型:按需实现

      • 没有类型 擦除
      • 具体类型
    • 子类保留父类的泛型:泛型子类

      • 全部保留

      • 部分保留

结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自 己的泛型

/*** 注意点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、有限制条件的通配符的使用

image.png

六、泛型应用举例

定义一个泛型类 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);}
}
查看全文

/2175423.html

相关文章:

  • [JAVAee]SpringBoot配置文件
  • Mysql----锁
  • 气传导耳机对耳朵有伤害吗?气传导耳机哪款好?
  • Java手写斐波那契数列算法和斐波那契数列算法应用拓展案例
  • 18.SpringTask 定时任务框架
  • 图论第四天|127. 单词接龙、841. 钥匙和房间、463. 岛屿的周长
  • 神经网络 02(激活函数)
  • 华为云云耀云服务器L实例评测|一个2C2G3M的云服务器能做哪些有有趣的事儿?
  • 有效的括号(栈的高频面试题)
  • 【数据结构】堆的应用+TOP-K问题+二叉树遍历
  • 数据库连接工具Chat2DB介绍
  • C# 流Stream详解(3)——FileStream源码
  • Vue Grid Layout -️ 适用Vue.js的栅格布局系统,在vue3+上使用
  • [maven] maven 创建 web 项目并嵌套项目
  • vue3-vant4-vite-pinia-axios-less学习日记
  • 二叉树题目:层数最深叶子结点的和
  • Java手写约瑟夫问题算法和约瑟夫问题算法应用拓展案例
  • innovus: 各种padding一勺烩
  • 简单的分析下dart实现grpc客户端的流程,以helloworld为例
  • stm32--独立看门狗
  • GcExcel:Java 应用创建、修改和保存 Excel 电子表格 -Crack
  • 腾讯mini项目-【指标监控服务重构】2023-08-19
  • leetcode363周赛
  • new/delete, malloc/free 内存泄漏如何检测
  • 无涯教程-JavaScript - ODD函数
  • 阿里云无影电脑:免费体验无影云电脑3个月
  • 嵌入式学习笔记(25)串口通信的基本原理
  • 前后端分离技术逐步深入,让你更加深入理解Nginx+Tomcat
  • Linux学习第11天:字符设备驱动开发:一字一符总见情
  • windows彻底卸载unity
  • 前端html原生页面兼容多端H5和移动端适配方案
  • 系统性能调优:提升服务器响应速度
  • PHP通过pem文件校验签名异常
  • 【C++ Exceptions】Catch exceptions by reference!
  • 科技资讯|苹果虚拟纸可在Vision Pro中为广告、书籍等提供MR内容和动画
  • webpack静态资源上传到CDNS (阿里云 OSS,亚马逊 AWS S3,七牛云 Qiniu Cloud Kodo)webpack-plugin-cdns
  • VMware workstation 中centos7虚拟机在nat模式下怎么配置网卡,指定我想要的IP并且可以联网
  • Flask 使用 JWT(一)
  • 【ant-design-vue】ant-design-vue在uniapp使用时,auto-import失败报错
  • 一文通览腾讯云大数据ES、数据湖计算、云数据仓库产品新版本技术创新
  • cuda以及pytorch安装
  • Xilinx FPGA 7系列 GTX/GTH Transceivers (2)--IBERT
  • oracle创建数据库以及用户,并导入dmp格式数据
  • 每个高级前端工程师都应该知道的前端布局
  • 微软发现影响 Linux 和 macOS系统的 ncurses 库漏洞
  • 前后端开发接口联调对接参数
  • 线性代数的本质(一)——向量空间
  • Maven 工具学习笔记(基础)
  • reg与wire的用法,证明reg可以在右边,wire型在左边,来作组合逻辑处理。
  • 【JDK 8-函数式编程】4.5 Predicate
  • html网页制作期末大作业-网上花店商城html+css+javascript
  • 2023年11月25日PMP报名正式开始!附操作指南
  • 伦敦银时走势与获利机会
  • 【数据结构】单值二叉树 相同的树 翻转二叉树(五)
  • 从0搭建夜莺v6基础监控告警系统(一):基础服务安装
  • three.js——模型对象的使用材质和方法
  • Java手写红黑树
  • 华为HCIA(四)
  • MyBatis面试题(一)
  • ARM cortex-A7核LED灯点灯实验
  • vue学习-01vue入门
  • K8s(Kubernetes)学习(六)——Ingress
  • 8种LED显示屏的安装方式
  • zabbix学习1--zabbix6.x单机
  • 一文了解水雨情在线监测站的优势
  • QSlider风格设置
  • GaussDB(DWS)云原生数仓技术解析:湖仓一体,体验与大数据互联互通
  • 项目性能优化 - 并发编程合并文章详情页的 HTTP 请求次数
  • linux基础篇
  • MATLAB中filloutliers函数用法
  • 蓝桥杯2023年第十四届省赛真题-买瓜--Java题解
  • OpenText EnCase Mobile Investigator 查看、分析和报告被调查手机的证据
  • 83 # 静态服务中间件 koa-static 的使用以及实现
  • 计算机网络第四章——网络层(下)
  • 09MyBatisX插件
  • JMeter基础 —— 使用Badboy录制JMeter脚本!
  • 蓝牙核心规范(V5.4)10.1-BLE 入门笔记(1)
  • Java实现图书管理系统
  • 评价模型:层次分析法
  • 【免费内网穿透】cpolar从0开始使用
  • 面试中常见的算法题和其python实现
  • flask+python快速搭建
  • 手把手教你搭建农产品商城小程序:详细步骤解析
  • 信息化助力高校教育统计数据质量的提升
  • 4G模块驱动移植
  • 软件测试团队必看:测试指标 TOP 3 榜单
  • 【seata】引入seata导致原本自定义实现的RequestInterceptor失效
  • SSM - Springboot - MyBatis-Plus 全栈体系(七)
  • TypeScript逆变 :条件、推断和泛型的应用
  • OpenStack创建云主机并连接CRT
  • 04Spring的核心配置文件
  • 构建个人图床云盘—EasyImage的简单部署及远程访问配置
  • 计算机网络选择题笔记
  • 【AI语言大模型】文心一言功能使用介绍
  • JSP ssm 网上求职管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计
  • 2021年电工杯数学建模A题高铁牵引供电系统运行数据分析及等值建模求解全过程论文及程序
  • List 获取前N条数据
  • 虹科分享 | 来自Redis7.2的一封信:亲爱的Programmer,当你......
  • 抖音小店经营指南:在兴趣电商背景下打造成功的抖音店铺
  • ts 泛型基础介绍
  • 99%的人还看了

    猜你感兴趣

    版权申明

    本文"Java高级之泛型、自定义泛型、通配符的使用":http://eshow365.cn/6-8924-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!