泛型擦除:
public class ErasedType {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}
Arraylsit源码:
public class ArrayList<E> extends AbstractList<E>implements List<E>,
~Output:
true
我们把一个Integer对象放入到String类型的集合中肯定会出错,因为两个集合的类型不同,但他们的class对象比较却是相同。这便是泛型擦除在捣乱。在运行的时候,不管是String类型还是Integer类型都被擦啦。
泛型理解:
在泛型代码内部我们无法获得任何有关泛型参数的信息
当我们在使用泛型时,任何具体的类型信息都被擦除了,我们唯一知道的就是在使用一个对象
无法知道创建摸个对象的特定实例
package com.package15;
import java.util.*;
class Frob{}
class Fnorkle{}
class Qurak<Q>{}
class Particle<POSITION,MOMENTUM>{}
public class LostInformation {
public static void main(String[] args) {
List<Frob> frobList = new ArrayList<>();
Map<Frob,Fnorkle> hashMap = new HashMap<>();
Qurak<Frob> Qurak = new Qurak<>();
Particle<Frob, Fnorkle> particle = new Particle<>();
System.out.println("froblist "+ Arrays.toString(frobList.getClass().getTypeParameters()));
System.out.println("hashMap "+Arrays.toString(hashMap.getClass().getTypeParameters()));
System.out.println("Qurak " +Arrays.toString(Qurak.getClass().getTypeParameters()));
System.out.println("particle "+Arrays.toString(particle.getClass().getTypeParameters()));
}
}
//~Output:
froblist [E]
hashMap [K, V]
Qurak [Q]
particle [POSITION, MOMENTUM]
getTypeParameters()用于获取此实体的类型参数。该实体可以是类,数组,接口等。该方法返回表示类型变量的TypeVariable对象的数组。
擦除的核心动机:
非泛化的类库可以去使用泛化的客户端。也就是说,当摸个类库变成泛型时,不会破坏依赖于它的代码和应用程序
擦除的代价:
泛型不能用于显示地引用运行时类型的操做之中,比如:转型、instanceod操做、new 表达式。因为所以关于参数的类型信息都丢失了,无论何时,当我们在编写泛型代码时,必须时刻提醒自己,你只是好像拥有有关参数的类型信息而已。
边界的运用:
1通过泛型使用某一类型的方法?
泛型的擦除机制使我们无法去使用显示的使用运行时类型的操作了。如果我们想要在泛型中使用一个一个类型的方法,那么程序就会报错。↓
问题:
public class HasF {
public void f(){
System.out.println("HasF.f() ");
}
}
class Manipulator<T>{
private T o;
public Manipulator(T o){
this.o = o;
}
public void manipulate(){
o.f();//无法使用类型方法
}
}
public class Manipulation {
public static void main(String[] args) {
}
}
解决方案:使用边界 通过extends来限定边界(!此时要注意对T的初始化),虽然使用边界符可以调用类型方法,但泛型擦除依然存在。
package com.package15;
import java.util.Arrays;
class HaseF{
public void f(){
System.out.println("Hase.F()");
}
}
class Manipulator<T extends HaseF>{
private T t;
Manipulator(T t){this.t=t;}
public void info(){
t.f();//无法使用泛型类型中的方法的
}
}
public class Manipulation {
public static void main(String[] args) {
Manipulator<HaseF> haseFManipulator = new Manipulator<>(new HaseF());
haseFManipulator.info();
//虽然使用边界符可以调用类型方法,但泛型擦除依然存在
System.out.println(Arrays.toString(haseFManipulator.getClass().getTypeParameters()));
}
}
2.通过使用边界,可以返回Woo及其子类,但不需要显示的类型转换。但泛型擦除依然存在。
package com.package15;
class Woo{}
class Hoo extends Woo{
}
public class GenericBoundaryApp<T extends Woo> {
private T t;
GenericBoundaryApp(T t){
this.t=t;
}
public T getTClass(){
return t;
}
public static void main(String[] args) {
GenericBoundaryApp<Woo> genericBoundaryApp = new GenericBoundaryApp<>(new Woo());
Woo tClass = genericBoundaryApp.getTClass();
System.out.println("返回了Woo"+tClass);
GenericBoundaryApp<Hoo> genericHoo = new GenericBoundaryApp<>(new Hoo());
Hoo tClass1 = genericHoo.getTClass();
System.out.println("返回了Woo的子类"+tClass1);
}
}