泛型的本质
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。在定义类,接口或方法时,可以使用一个或多个类型参数来表示参数化类型。
java 中泛型标记符
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
泛型的好处:
1.统一数据类型
2.把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常
泛型的细节:
1.泛型不能写基本数据类型
2.指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
3.如果不写泛型,类型默认是Object
泛型可以在多个地方进行定义:
- 类后面 (泛型类)
- 方法上面(泛型方法)
- 接口后面(泛型接口)
泛型类
1)使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
2)格式:
修饰符 class 类名<类型>{
}
public class ArrayList<E>{ //创建该类对象时,E就确定类型
//此处E可以理解为变量,记录数据的类型。E还可以写成T、E、K、V等
Object[] obj = new Object[10];
int size;
public boolean add(E e){ //E:表示不确定的类型。e:形参的名字,变量名
obj[size] = e;
size++;
return true;
}
public E get (int index){
return (E)obj[index];
}
}
MyArrayList<Integer> list = new MyArrayList<>();
泛型方法
使用场景:
方法中形参类型不确定时
方案①:使用类名后面定义的泛型(所有方法都是适用)
方案②:在方法申明上定义自己的泛型(只有本方法能用)
格式:
修饰符<类型>返回值类型 方法名(类型 变量名){
}
public <T> void show (T t){ //此处的T可以理解为变量,用来记录类型,也可以写成T、E、K、V等
}
在网上找的一个实例:
运行结果如下:
泛型接口
格式:
修饰符 interface 接口名<类型>{
}
public interface List <E> {
}
如何使用一个带泛型的接口
方法一:实现类给出具体类型
方法二:实现类延续泛型,创建对象时再确定
泛型的继承和通配符:
泛型不具备继承性,但是数据具备继承性
泛型的通配符:?,表示不确定的类型,可以进行限定类型的范围
<? extends T>和<? super T>的区别
- <? extends T>表示该通配符所代表的类型是T类型的子类,可以传递T或者T所有的子类类型
- <? super T>表示该通配符所代表的类型是T类型的父类,可以传递T或者T所以的父类类型
应用场景:
1.如果我们在定义类,方法,接口的时候,如果类型不确定,就可以定义泛型类,泛型方法,泛型接口
2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符
总结:
- 泛型的定义:JDK5引用的特性,可以在编译阶段约束操作的数据类型,并进行检查
- 泛型的好处:
1.统一数据类型
2.把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常
- 哪里定义泛型:
泛型类:在类名后面定义泛型,创建该类对象的时候,确定类型
泛型方法:在修饰符后面定义泛型方法,调用该方法时,确定类型
泛型接口:在接口名后面定义泛型,实现类确定类型,实现延续泛型
- 泛型的继承和通配符:
泛型不具备继承性,但是数据具备继承性
泛型的通配符:?,表示不确定的类型,可以进行限定类型的范围
<? extends T>表示该通配符所代表的类型是T类型的子类,可以传递T或者T所有 的子类类型
<? super T>表示该通配符所代表的类型是T类型的父类,可以传递T或者T所以的
父类类型