java 协变性_Java基础:泛型及其擦除性、不可协变性

编译擦除后,生成的类是这样:

class TObject

{

privateObject obj;

publicvoid Set(Object object)

{

this.obj= object;

}

}

首先泛型参数T被向上替换为自身的顶级父类Object,然后将类型参数T去除。

(3)自定义继承关系泛型类型擦除:

class Manipulator

{

private T obj;

public Manipulator(T x){

obj = x;

}

public void doSomething(){

obj.f();

System.out.println(obj.getClass().getName());

}

}

首先将泛型参数T向上替换为上边界,然后去除泛型参数:

class Manipulator

{

private SuperClass obj;

public Manipulator(SuperClass x){

obj = x;

}

public void doSomething(){

obj.f();

System.out.println(obj.getClass().getName());

}

}

三、擦除原因:

泛型不是在java一开始就有的,擦除是java中泛型实现的一种折中手段。

具体来说两个原因使得泛型代码需要类型擦除:

(1)引入泛型代码不能对现有代码类库产生影响,所以需要将泛型代码擦除为非泛型代码;

(2)当泛型代码被当做类库使用时,为了兼容性,不需要知道泛型代码是否使用泛型,所以需要擦除;

5不可协变:

(1)数组和泛型对比

数组是可协变的、泛型是不可协变的。

什么是可协变性?举个例子说明:

数组可协变(covariant)是指如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。

泛型不可变的(invariant)是指List不会是List的基类,两者压根没关系。

(2)泛型为什么不可协变

泛型“编译时进行类型检查(类型安全)”特性决定了其不可协变。

ArrayList objList = new ArrayList();

//can't compile pass

类型安全检查

Object[] objArray = new Long[10];

//compile OK

如果ArrayList类型对象可以赋值给ArrayList类型引用,那么就违反了泛型类型安全的原则。

因为如果编译器你这样做,会导致可以往容器中放置非Long型的对象。但是数组就无所谓,他不是类型安全的。

再看看下面代码,第一行编译错误是因为不可协变性,那么为什么第二行可以呢?

List listt = new ArrayList();

//can't compile pass

List extends Type> listt = new ArrayList();

//OK

参考泛型通配符,这就是其作用

不可协变并不代表不能在泛型代码中将父类出现的地方使用子类代替,如下面代码是合法的:

ArrayList list = new ArrayList();

//Type is SuperClass

list.add(new SubType());

//SubType is SubClass

Type[] tt = new Type[3];

tt[0] = new SubType();

(3)数组可协变带来的问题:

数组的协变性可能会导致一些错误,比如下面的代码:

public static voidmain(String[] args) {

Object[] array = new String[10];

array[0] = 10;

}

它是可以编译通过的,因为数组是协变的,Object[]类型的引用可以指向一个String[]类型的对象。但是运行的时候是会报出如下异常的:

Exception in thread"main" java.lang.ArrayStoreException: java.lang.Integer

但是对于泛型就不会出现这种情况了:

public static voidmain(String[] args) {

List< Object> list = newArrayList< String>();

list.add(10);

}

这段代码连编译都不能通过。

6.通配符:

通配符在类型系统中的作用部分来自其不会发生协变(covariant)这一特性。即通配符产生一部分原因来自突破不可协变的限制。

可以认为通配符使得List>是List的基类,List extends  Type>是List的基类。

// collection1可以存放任何类型

Collection>collection1 = new ArrayList();

collection1 = newArrayList();

collection1 = newArrayList();

//collection3表示它可以存放Number或Number的子类

Collection<?extends Number> collection3 = null;

collection3 = newArrayList();

collection3 = newArrayList();

collection3 = newArrayList();

//collection4表示它可以存放Integer或Integer的父类

Collection superInteger> collection4 = null;

collection4 = newArrayList();

22/2<12

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值