泛型是JDK 1.5的一项新增特性,它的本质是参数化类型(ParametersizedType)的应用,也就是说所操作的数据类型被指定为一个参数(是不是像lambda表达式差不多的用义,用函数作为一个方法的参数)。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
具体来说,我们先通过对比下代码,来进一步体会泛型的好处
先看看没有支持泛型之前的代码
没有运用泛型的代码
运用泛型的代码示范
由以上两个例子可以看出:
引入泛型后,代码在前端编译的时候会做检查,不会像1.5的代码示范一样,直到程序运行期才提示异常。通过现代idea自动编译功能,由此可以大大提高我们的编程效率
但是有关java的泛型有一些值得思考的问题:
方法重载
编译异常
代码示范:用两个不同List类型参数重载getName方法编译报错,why?
以上现象是因为在编译时泛型擦除造成的,什么? 泛型擦除又是什么鬼?
我们可以通过字节码来分析这个问题
代码示范
字节码片段
然后用jd-gui工具反编译回java代码
反编译后的代码
通过对比可以看出,反编译的代码跟我们之前写的代码不一致了,代码风格也用回1.5之前的强制类型转换了,即高版本支持某些语法糖的编程风格编译之后转化为低版本代码风格了(解语法糖)
现在我们可以知道为什么用两个不同List类型参数重载getName方法会编译报错了:
两个不同List类型参数,在编译的时候都转为List了,然后就不符合重载的定义了
所以有个哲学上的问题:
List
List
其实这两个类型不是真正意义上的类型,他们在某种意义上还是一个List类型,只是套了层修饰,这种表面上的修饰作用很有利于编程人员,过了编译期,这种修饰就没有意义了,当然,为了运行期反射来获取这种修饰符号,在编译成字节码时,增加了一些属性来记录这个具体的类型,解决伴随泛型而来的参数类型的识别问题,如如Signature、LocalVariableTypeTable
Signature和LocalVar
所以有个说法是:java实现的泛型,其实不是真正意义上的泛型,是伪泛型