JavaSE泛型的那些事(泛型考古泛型擦除包装类)
一。什么是泛型
泛型(generictype)其本质是将类型参数化,也就是说所操作的数据类型被指定为一个参数这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。二。为什么要有泛型?
之前写过MyArrayList顺序表,这个类当时自己在实现的时候只能用一种类型来表示,也就是用的时候自己实现的MyArrayList只能应用于一种类型,要想应用于其他类型,就得再写一个其他类型的MyArrayList,这样就比较麻烦,而有了泛型之后就很好的解决了这个问题,让类型参数化,使得自己写的MyArrayList可以适用于多种场景
通过以下代码对比就可发现泛型的方便之处
示例
不带泛型
publicclassMyArrayList{
privateint〔〕array;
privateintsize;有效数据个数
publicMyArrayList(){
this。arraynewint〔10〕;
this。size0;
}
publicvoidadd(intx){暂不考虑扩容
this。array〔size〕x;
this。size;
}
}
带泛型
importorg。omg。CORBA。Object;
publicclassMyArrayList2{
在类的实现中,可以直接将类当成一种数据类型来使用。在实例化该类的时候这个类型才被确定
privateE〔〕array;
privateintsize;有效数据个数
publicMyArrayList2(){
this。array(E〔〕)newObject〔10〕;注意:Java中泛型不允许定义数组
this。size0;
}
publicvoidadd(Ee){不考虑扩容
this。array〔size〕e;
this。size;
}
}
带泛型的顺序表元素类型是一个变量
E就是变量的名称
通过上面这两段代码的对比,就可以发现,带泛型的顺序表和不带泛型的顺序表只是表示类型的部分不一样,代码所实现的逻辑是一样的
类的实例化与使用
publicstaticvoidmain(String〔〕args){
MyArrayListmyArrayListnewMyArrayList();
myArrayList。add(1);
myArrayList。add(2);
这里其实就相当于是将String类型赋值给E
MyArrayList2stringMyArrayList2newMyArrayList2();等号右边的内可以省略
stringMyArrayList2。add(1);要想用基本类型,要写基本类型对应的包装类
stringMyArrayList2。add(2);
}
对于泛型来说,类型是在使用该类时才明确定义出来的三、泛型考古
要知道其实刚开始Java体系中是没有泛型的,是在JDK1。5之后才才有了泛型
在JDK1。5之前是利用Object引用可以指向任意类型的对象实现类似泛型的效果Object类是所有类的祖先类上层引用可以指向下层对象
如下代码:
publicclassMyArrayList3{
privateObject〔〕array;
privateintsize;
publicMyArrayList3(){
this。arraynewObject〔10〕;
this。size0;
}
publicvoidadd(Objecte){
this。array〔size〕e;
size;
}
}
这种做法的缺点也很明显,就是new了一个MyArrayList,里面打算存int类型的数据,但由于手滑,存入了一个String类型的数据,这样的话编译器是不会报错的,程序也能正常运行,直到需要取list中的元素的时候程序才会抛出异常。
泛型就很好的解决了这个问题,只要类型不匹配,错误会在第一时间暴露出来四、泛型擦除
虽然在JDK1。5之后有了泛型,但其实JDK的底层实现还是用的上面Object来实现的
如下图
我们虽然用的是泛型,但其实泛型只存在于编译阶段,在编译过程中也伴随着泛型擦除,在生成。class文件的时候泛型信息就已经不存在了,成了JDK1。5之前的Object方式
查看MyArrayList的字节码文件就可以看出来
所以Java的泛型只存在于编译阶段(Java核心原理:Object引用可以指向任意类型的对象)五、包装类
由于8种基本类型不是类类型,Java专门为它们定义了各自的包装类
如下:
bytejava。lang。Byte
shortjava。lang。Short
charjava。lang。Character
intjava。lang。Integer
longjava。lang。Long
floatjava。lang。Float
doublejava。lang。Double
booleanjava。lang。Boolean六、装箱、拆箱
Java中提供了便利,如果没有歧义,Java会帮我们自动装箱,自动拆箱
Integera10;把int赋值给Integer类型,隐含着发生了装箱过程
intba;把Integer赋值给int类型,隐含着发生了拆箱过程
隐式装箱和拆箱过程只存在于编译阶段,编译完成就变成显式装箱,显式拆箱了