Java泛型

泛型定义

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型(类型实参)。

假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?

答案是可以使用 Java 泛型

使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。

泛型原理:

泛型是java5才引入的,虚拟机其实并不支持泛型,为了向下兼容,Java在编译期间擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在Java运行时根本就不存在泛型信息。

编译器如何擦除泛型:

  • 检查泛型类型,获取目标类型
  • 擦除类型变量,并替换为限定类型
    • 如果泛型类型的类型变量没有限定,则用Object作为原始类型
    • 如果有限定,则用Class1作为原始类型
    • 如果有多个限定类型,则使用第一个边界Class1作为原始类
  • 在必要时插入类型转换以保持类型安全
  • 生成桥方法以在扩展时保持多态性
  • 可以对比下类经过编译后的生成的字节码:
    从下图1可以看见泛型都没了,add和get方法的T都被Object替代了,这就是编译器擦除了泛型
    图1.png

    从下图2可看到如果有限定符,被擦除后则用限定类型替代。
    图2.png

    从下图3看出编译后插入了类型转换
    图3.png

    如下图4,图5,根据泛型擦除我们知道,接口CageInterface的get方法编译后其实是public Object get(){};而Cage的get方法被限定为public Animal get(){},所以编译器会实现一个桥方法,内部再去调用public Animal get(){}方法,这样就保持了多态性。
    图4.png
    图5.png

限定通配符(为了更灵活的转型):

  • 上界通配符(通常用于取数据):

图6
如上图6 ,编译器报错,无法add,因为是限定animals这个引用类型范围是Animals或者其子类,只是代表这个范围,并不是具体某个引用类型,所以没法与任何类型匹配,add任何都报错(除了null),但是get是可以的,他一定是Animal的子类,只要用其父类接收就可以。

  • 下界通配符(通常用于接收数据):

图7.png
如上图7,因为是限定animals引用类型范围是Animal或者它的父类(并非代表其指向的具体ArrayList对象存放的是Animal或者其父类),所以animals可以add任何Animal子类以及Animal,因为这些一定是这个引用类型的子类;也可以get,但是只能用Object接收,否则如上编译器报错,因此get没什么意义。

这时候可以看一下Collections集合类的copy泛型方法:
public static void copy(List dest, List src)
可以看到src参数使用了上界通配符,dest参数使用了下界通配符,意味着src引用所指向的列表一定是T或者T的某个子类型,而dest引用范围是T或者它的父类,所以将src中的元素复制到dest一定是可以的,所以保证了从src复制到dest的类型正确性。

非限定通配符:

如List,既不能读也不能写,等价于List,对于List编译器会进行安全检查,而List不会。

你可能感兴趣的:(Java泛型)