关于JAVA泛型的理解
关于java泛型的理解,泛型是java5.0增加的一种新的机制,与c++的模板很相似但却有很多的不同,当然我对c++的理解并不多,对于java泛型的理解我从以下几个方面总结一下,当然,也许会有错误,毕竟学习还不是很深刻,仅阶段性总结。
为什么要引入泛型:
在泛型出现之前java中当然也是有一个ArrayList用来存储各种对象,对于代码可读性是一个问题,最重要的是对于使用ArrayList的安全性有很严重的问题,由于要适应存储各种类型变量,ArrayList内部使用Object来存放对象,这就产生了两个问题,<1>如果你只想存入String类型,但存入的对象可以是任何其他对象。<2>取出时要进行强制类型转换,结合第一点,你并不知道你要转换的可能并不是你想要的,此时就要出错。并且这些错误并不会在你编译时提示你。因此,引入泛型就显得很必要。
泛型的实现原理:
泛型中用<>来限定类型变量,如ArrayList,既然限定了类型变量,当然就很好的解决了之前的痛点,在进行编译时,只能存储读取已经指定类型的变量,当你试图存储其他类型的变量时,编译器便会报错,这在安全性与可读性上都有了很大的改变。
然而,java中的泛型仅是一种伪泛型,这也是他与c++中模板类本质的区别,jvm虚拟机中并不存在泛型这种对象,泛型的“存活期”仅在程序进行编译前,或许可以这样说,java的泛型是通过编译器来实现的。
这里要提到两个名词“原始类型”与“类型擦除”这是理解泛型极为重要的两个概念。所谓类型擦除应该很容易理解
例如:
```
test
```
进行类型擦出后,则变为:
类型参数被擦除后的代码便是原始类型,每一个泛型都对应一个原始类型。
那么问题来了,将参数擦出之后,存取时还怎么识别限定参数类型,编译器会替我们做这一切,当调用demo.getT()方法时会返回一个object对象,编译器会在翻译程序时会在方法调用后插入一条强制类型转换指令,对于set()方法,在编译程序前会由编译器对泛型进行检查,当引用的不是限定的类型变量时,编译器就会报错。由此,这些对于我们来说都是不可见的。
然而类型擦除造成了继承上的一些问题,例如:
该方法继承并重写了父类方法中的get,set方法,那么在编译进行类型擦除后如何保证多态特性,以及方法的签名问题,加入直接进行擦出会直接产生两个setT(Object)与Object get()方法。此时编译器会为我们出现冲突的程序添加一个“桥方法”,表面解读就是桥梁的意思,添加桥方法后编译后程序中拥有的方法为:
乍一看有点奇怪,第一个和第三个方法都是编译器替你添加的桥方法,setT()还能理解,但getT()难道不会签名冲突,如果是我们自己写当然不会通过编译,但是在虚拟机运行时这样的写法是正确的,虚拟机会根据返回的参数来确定你调用的是哪个方法。