泛型
Java 泛型(generics)是JDK5中引入的一种参数化类型
1,为什么需要泛型
- 代码更强健,类型检测提前到编译期,便于早发现错误
- 代码更简洁,避免使用的时候需要强制转换
- 代码更灵活,多种数据类型使用同样的代码 ,代码复用
2,泛型类
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
引入一个类型变量T(其他大写字母都可以,不过常用的就是T,E,K,V等等),并且用<>括起来,并放在类名的后面。泛型类是允许有多个类型变量的。
public class Normalgeneric<T> {
private T data;
public Normalgeneric(T data) {
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
Normalgeneric<String> normalgeneric = new Normalgeneric<>("hello java");
System.out.println(normalgeneric.getData());
}
}
3,泛型接口
public interface genertor<T> {
public T text();
}
泛型类实现泛型接口
class Generisc implements Normalgeneric{}
普通类实现泛型接口
class Generisc implements Normalgeneric{}
4,泛型方法
6,类型变量的限定
public static <T extends ArrayList & Comparable & Serializable> T min(T a,T b){
if(a.compareTo(b) > 0) return a;
else return b;
}
继承的可以是类,也可以是接口,具有多个限定类型的话,类必须在第一个且只能有一个类
7,泛型的约束和局限性
不能用基本类型实例化类型参数
不能实例化类型变量
public class Normalgeneric<T> {
public <T> T genericMethod(T data){
return data;
}
private T data;
public Normalgeneric(T data) {
//this.data = data;
//不可以这样实例化
this.data = new T();
}
静态域或者方法里不能引用类型变量。
泛型的类型在对象创建的时候才知道泛型的类型,但是static对象的创建的时候先执行static方法,虚拟机根本不知道T是什么类型。静态泛型方法是允许的。
关于泛型的实例化类型所有的基本类型都是不可以的。只允许包装类。
泛型不允许用instanceof
可以定义泛型数组,不能创建数组
泛型类不能extends Exception/Throwable
不能捕获泛型类对象
8,泛型类型的继承规则
两个继承关系的类,在泛型里面没有任何关系
泛型类可以继承或者扩展其他泛型类,比如List 和ArrayList
9,通配符
? extends X
表示传递给方法的参数,必须是X的子类(包括X本身)
orange 继承fruit。?设置了参数的上界,主要用于安全的访问数据
? super X
表示传递给方法的参数,必须是X的超类(包括X本身)
设置了参数的下届,只能写数据,不可以读
set的时候只能添加本身和子类
10,虚拟机是如何实现泛型的
伪泛型,泛型到jdk变成object类型,有extends会变成后面的第一个,
编译成字节码做了类型的擦除
11,泛型的面试题
Q:Java泛型的原理,什么是泛型擦除机制?
Java 的泛型是JDK5 才引入的一种特性,为了向下兼容,虚拟机其实不支持泛型,所以Java实现的是一种为泛型机制,也就是说Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在Java运行时根本不存在泛型信息。
Q:Java编译器具体是如何擦除泛型的
1,检查泛型类型,获取目标类型
2,擦除类型变量,并替换为限定类型
如果泛型类型的类型变量没有限定,则用Object作为原始类型
如果有限定,则用Xclass作为原始类型
如果有多个限定<T extends Xclass & Xclass2> ,则使用第一个边界XClass作为原始类
3,在必要时插入类型转换以保持类型安全
4,生成桥方法以在扩展时保持多态性