Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 309|回复: 0

[泛型学习]数组的协变性与范型的不可变性

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-28 23:55:31 | 显示全部楼层 |阅读模式
    记得以前面试的时候曾被问过一个问题:数组和List的区别是什么?当时答的无非就是效率,容量固定,List不能存基本类型等等。当java发展到了1.5之后,出现了泛型版本的List,又为这个问题的解答加入了一笔。下面就来讲一下与这个话题相关的内容。

    1. 数组的协变性。
        数组的协变性(covariant)是指如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。而泛型是不可变的(invariant),List<Base>不会是List<Sub>的基类,更不会是它的子类。

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

    1. public static void main(String[] args) {   
    2.    Object[] array = new String[10];   
    3.   array[0] = 10;   
    4. }                        
    复制代码

      
       
       
         
       

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

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

    原因就像呼吸一样简单。

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

    1. public static void main(String[] args) {   
    2.     List< Object> list = new ArrayList< String>();   
    3.     list.add(10);   
    4. }  
    复制代码
    这段代码连编译都不能通过。

    2. 数组的具体化。
       第二个要讲的问题是数组是具体化的(reified),而泛型在运行时是被擦除的(erasure)。这句话的意思是数组是在运行时才去判断数组元素的类型约束,而泛型正好相反,在运行时,泛型的类型信息是会被擦除的,只有编译的时候才会对类型进行强化。

    所以上面的例子中,数组的方法会在运行时报出ArrayStoreException,而泛型根本无法通过编译。

    3. 泛型与数组的结合。
    这个问题的标题有些误导,其实泛型与数组根本没有任何结合的可能性。List<E>[]、List<Integer>[]、或者E[]的写法都是错误的。因为这些方法无法提供类型的安全性。我们来分别举2个例子来说明它们会导致的错误。

    1. public void testMethod1() {   
    2.     List< Integer>[] array = new List< Integer>[10];   
    3.     List< String> list = new ArrayList< String>();   
    4.     Object[] objs = array;   
    5.     objs[0] = list;   
    6. }  
    复制代码
    这段代码假设array这个泛型数组是可以被创建的,那么它就可以被Object[]类型的变量引用,进而导致了array中的元素变成了List<String>类型了,发生了类型错误。

    第二个例子是关于类型参数数组的:

    1. public < E> void testMethod2(E e) {   
    2.     E[] array = new E[10];   
    3.     Object[] objs = array;   
    4.     objs[0] = e;   
    5.     objs[1] = "string";   
    6.     objs[2] = 10;   
    7.     objs[2] = true;   
    8. }  
    复制代码
    与上边的那个例子相似,array可以放入任何类型的元素了,这个是很不安全的。  这里有一个例外的情况可以说一下,无限制通配符类型的泛型是可以创建泛型数组的。  List< ?>[] listArray = new List< ?>[10];  

      
      
       
       

         
       

         
       
      
    复制代码
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-26 04:13 , Processed in 0.357772 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表