[2025.1.14 JavaSE学习]泛型
为什么需要泛型
对传统问题进行分析
- 不能对加入到集合ArrayLsit中的数据类型进行约束(ArrayList存放Object,任何类型都可以加入到其中,但是之后向下转型会出现问题)
- 遍历的时候,需要进行类型转换,如果数据量较大,会对效率产生影响
- 快速使用案例:
ArrayList<Dog> arr = new ArrayList<Dog>();
arr.add(new Cat());//会直接报错
泛型介绍
- 泛型又称参数化类型,为jdk5.0新特性,解决数据类型的安全性问题
- 在类声明或实例化时只要指定好需要的具体的类型即可
- Java泛型可以保证:如果程序在编译时没有发生警告,运行时就不会产生ClassCastException异常
- 泛型的作用:在类声明时,通过一个标识表示类中某个属性的类型,或者某个方法返回值的类型,或者参数类型(编译期间,就知道该泛型的具体类型)
泛型应用
泛型的声明
- 接口:interface 接口名< T >{}
- 类:class 类名<K, V>{}
泛型的实例化
泛型的实例化和不使用泛型的实例化相似,只需要加上<>即可
泛型使用的一些注意细节
- 泛型的数据类型必须是引用类型,不能是基本数据类型
List<Integer> list = new ArrayList<Integer>();//Correct
List<int> list2 = new ArrayList<int>();//Wrong
- 在给泛型指定具体类型后,可以传入该类型和该子类类型
- 在实际开发中,我们一般简写,编译器会进行类型推断:
//origin
List<Integer> list = new List<Integer>();
//simple
List<Integer> list_ = new List<>();
- 默认写法下,泛型默认是Object
ArrayList list = new ArrayList();
//等价于
ArrayList<Object> list_ = new ArrayList<Object>();
自定义泛型类
细节
- 普通成员可以使用泛型(属性、方法)
- 使用泛型的数组不可以用new进行初始化,因为编译时T还未清楚具体类型,无法分配空间
T[] ts_;
T[] ts = new T[8];//不行!!!
- 静态方法和属性不可以使用类的泛型,因为类加载时就加载了静态方法和属性,而此时还未进行泛型类实例化,不能确定T具体类型
- 泛型类的类型,是在创建对象(实例化)时确定的
自定义泛型接口
细节
- 接口中,静态成员不能使用泛型
- 泛型接口的类型,在继承接口或者实现接口时确定
- 1、继承时,要指定继承泛型接口的具体类型
- 2、类实现泛型接口,也需要指定泛型接口的具体类型
- 没有指定类型,默认也为Object
自定义泛型方法
基本语法
修饰符 <T, R, ...>返回类型 方法名(参数列表){}
细节
- 泛型方法,可以定义在普通类中,也可以定义在泛型类中
- 当泛型方法被调用时,泛型具体类型确定
- public void eat(E e){},此种情况修饰符public后没有<>,不是泛型方法,而是使用了泛型
泛型的继承和通配符说明
- 泛型不具备继承性
List<Object> list = new ArrayList<String>();
//不可以!!!
- <?>:支持任意泛型类型
- <? extends A>:支持A类以及A类的子类,规定了泛型的上限
- <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限