1. 泛型
1.1. 泛型的必要性
集合中能够存储任意类型的数据, 但取出来的时候都是
Object
类型的,
此时需要进行强制类型转换, 才能将元素恢复成原来的类型.在实际使用中, 集合存储的元素的类型必须规定统一, 否则在一些集合中会出现混乱.
因为有的集合例如树形集合, 会自动对存入的元素进行比较操作, 类型不同无法比较.
1.2. 泛型的概念
- 泛型(Generic Type), 是从 JAVA5 开始支持的新的语法.
- 泛型指的是广泛通用的类型
- 泛型在代码模板中类型不确定, 根据调用者来指定数据类型
- 泛型实际上是语法糖, 在底层实际依旧使用的是强制类型转换
1.3. 泛型类
泛型类指的是在类或接口中定义了泛型的类/接口.
泛型类的定义可以在类后面加一对尖括号, 并在尖括号中定义对泛型的代称.
类中的泛型成员变量或方法会根据调用者指定的元素类型, 进行转换.
1.3.1. 泛型类的定义
示例:
public class Point<T>{ public T x; public T y; public T setX(T x) this.x = x; public T setY(T y) this.y = y; public T getX() return x; public T getY() return y; //... }
最常用的泛型代号缩写一般是:
T:type, E:Element, K:Key, V:Value
1.3.2. 泛型类的调用
元素的实际类型取决于调用者的指定, 调用时前后指定的类型必须一致.
若对泛型类不指定类型进行调用, 则默认为
Object
类型.实际调用可以省略后面尖括号的类型指定, 从 JAVA7 后出现的新泛型语法.
示例:Point<String> p1 = new Point<>();
泛型之中不存在继承关系, 即如下写法是错误的:
Point<Object> p1 = new Point<String>();
如下实例将对前面的泛型类进行调用.
public class Test{ public static void main(String[] args){ //前后尖括号内的类型必须一致 Point<String> p1 = new Point<String>(); p1.setX("1"); p1.setY("1"); Point<Integer> p2 = new Point<Integer>(); p2.setX(1); p2.setY(1); } }
1.4. 泛型方法的定义和使用
泛型方法:
指的是在方法上声明泛型.一般的, 把自定义的泛型作为方法的返回类型才有意义.
而且此时的泛型必须是由参数设置进来的.
如果没有参数来设置泛型的具体类型,
此时的方法一般返回设计为Object
即可.
如下实例定义:public static <T> T getElement(T ele){ return ele; }
1.4.1. 泛型方法的使用情景
- 情况1:
泛型类中的泛型只能适用于非静态方法.
所以静态方法只能使用泛型方法, 不能使用泛型类. - 情况2:
泛型类中的泛型适用于整个类中多个方法.
有时只需要一个方法设置泛型, 则要用到泛型方法.
1.5. 泛型通配符和上限下限
1.5.1. 泛型通配符
概念:
不知道使用什么类型来接收的时候, 可使用<?>
表示未知.注意:
使用通配符的集合只能接收数据, 不能向集合中存储数据.
一般用在形参上面, 如下方法所示:public static void function(List<?> list){}
1.5.2. 泛型的上下限
概念:
用来限定元素的类型必须是 X 类的子类或相同, X 类的父类或相同.
(一般来说这个方法用的不多).实例:
- 限定泛型的上限:
此时泛型使用<?>
, 接收的泛型必须是Number
类或其子类public static void fun1(List<? extends Number> list){}
- 限定泛型的下限:
此时泛型使用<?>
, 接收的泛型必须是Number
类或其父类public static void fun2(List<? super Number> list){}
- 限定泛型的上限:
1.6. 泛型的擦除和转换
1.6.1. 泛型的擦除
泛型编译之后就消失了(自动擦除)
当把带有泛型的集合赋给不带泛型的集合, 此时泛型被擦除(手动擦除)
下面是手动擦除的实例://定义带有泛型的集合 list1 List<Integer> list1 = new ArrayList<>(); list1.add(111); //定义不带泛型的集合 list2 List list2 = null; //当带有泛型的集合赋给不带泛型的集合时, 泛型被擦除 list2 = list1; //因为 list2 没有限定类型, 因此可加入任意类型数据 list2.add("str"); //输出结果是 [111, str] System.out.println(list2);