数组和泛型的协变性

数组协变性 ,泛型不可协变性

数组的协变性:如果类A是类B的子类,那么A[]是B[]的子类
泛型(<>)不可协变性:如果类A是类B的子类,List<A>List<B>毛线关系都木有

举个例子

Object[] obj = new String[]{};

这个写法是完全OK的,编译通过,而且即便在obj中存放了非string对象,也会在运行时才报异常
这就是数组的协变性,Object[] 是 String[] 的父类

ArrayList<Object> obj = new ArrayList<Integer>();

这个写法完全是错误的,连编译都不通过,因为泛型的非协同性,List<Object>LIst<Integer>是完全没有关系的两个类 ,那有怎么能new

那么为什么呢

数组为什么是协变性的

数组的协变性来源于数组的一个优势
数组记得它内部元素的具体类型,并且会在运行时做类型检查

也正是因为数组会在运行时做类型检查,在String[]插入一个Integer会报错,这也保证虽然数组是协变性的,依然能保证安全

泛型为什么是不协变性的

那么泛型为什么不是协变性的呢,为什么不能为泛型添加运行做类型检查的机制呢,这是因为泛型的一个特性——擦除性

泛型的擦除性

擦除性:去除泛型类型中所有的类型参数信息,只映射为一份字节码,具体的参数信息只能在静态编译期保留。(这个擦除性在泛型中详细解释,包括如何擦除的等等)

所以,作为只能在编译器保留类型的泛型,只能选择在编译期进行类型检查,因为一旦运行起来这个类型就被擦除掉了呀呀呀,这也就是为什么ArrayList<Object> obj = new ArrayList<Integer>(); 编译不会通过的原因。

那么如何能让泛型拥有类似协变性的功能呢

那么再次回到通配符的问题了
像这种实例化对象时使用通配符? ,我好像在哪篇里面写了,在这里再强化一下好了

<? extends xx>
<? super xx>

这样

ArrayList<? extends Object> list = new ArrayList<Integer>;

就OK了,我记得原来说<? extends xx>表示的是xx的一个子类,再并不在意是什么类型,当时书上还写是为了向上转型,这样就串起来了
PS : 是一种类型嗷嗷嗷啊,?表示的也是xx中确定的一种类型

泛型不可协变性的混淆点

父类A 子类B
泛型的不可协变性是说List<A>List<B>没有关系
可没有改变类A 和 类B之间的继承关系,类A的对象和类B的对象依然是可以转型的

但是这里注意一下,向上转型的主客问题,向上转型是子类B转成父类A,存放在父类A的List中
即父类的List中存放子类对象

        ArrayList<Object> list = new ArrayList<Object>();
        Integer i = new Integer(2);
        list.add(i);

这个代码OKOK的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值