1. 数组和泛型列表的区别

1. 数组是协变的,列表是可变的

如果Sub是Super类的子类,那么数组Sub[]就是Super[]的子类型
而List不是List的子类,List也不是List的超类。

2. 数组是具体的,无法使用泛型

List中的泛型是为了保证java新旧版本代码的兼容进行泛型擦除,但是数组中不涉及这些,因此无法在数组中使用泛型。创建泛型类型的数组,参数化类型的数组,以及类型参数的数组都是非法的。 因此,这些数组创建表达式都不合法:new List <E> []new List <String> []new E []。 所有将在编译时导致泛型数组创建错误。

2. 例子

图片.png
结合第一条,数组是具体化的,数组在运行时知道类型为Long,然后向上转型成Object,而泛型是不可具体的,List不是ArrayList超类,编译时看重类型,编译通过后泛型擦除,运行期间就丢弃类型信息。所以上述代码,数组在编译器可以通过,但是当运行期要输出的时候会抛出异常,而泛型直接会因为类型不对,无法通过编译。
上述代码注释掉list部分后,会抛出如下异常:,数组运行期输出报错

  1. Exception in thread "main" java.lang.ArrayStoreException: java.lang.String
  2. at item27.Test.main(Test.java:14)

总结:数组和泛型有着不同的类型规则,数组是协变且具体化的。泛型是不可变的且可以被擦除。按我的理解,协变和不可变是针对编译期的,例如:Object[] array = new Interger[10];数组可以向上转型,左边的引用类型可以是右边对象的超类。而List list= new ArrayList();无法通过编译,因为List并不是List的超类,编译器无法通过。这就是所谓的协变和不可变。而具体化和不具体化,是指虽然数组通过了编译器,但是存在着类型的转换,那么在运行期间需要转型,如上述的代码,如果转型的类型不对,会报错。但是List不会在运行期间出现这种问题,编译器会确保编译的时候不会出现问题,编译结束类型擦除,不会再因为类型转换上的问题出错。或者可以这么说,List只要编译通过就不会出现类型上的问题,数组编译通过,有可能会因为类型转换的问题在运行期间报错