🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
我们先来看一个简单的例子,Apple是Fruit的子类,思考下Apple[]和Fruit[],以及`List<Apple>`和`List<Fruit>`是什么关系呢? Apple[] appleArray = new Apple[10]; Fruit[] fruitArray = appleArray; //允许 fruitArray[0] = new Banana(0.5); //编译通过,运行报ArrayStoreException List<Apple> appleList = new ArrayList<Apple>(); List<Fruit> fruitList = appleList; //不允许 我们发现一个奇怪的现象,Apple[]类型的值可以赋值给Fruit[]类型的值,而且还可以将一个Banana对象添加到fruitArray,编译器能通过。作为对比,`List<Friut>`类型的值则在一开始就禁止被赋值为`List<Apple>`类型的值,这其中到底有什么不同呢? 其实这里涉及一个关键点,**数组是协变的,而List是不变的。简单来说,就是Object[]是所有对象数组的父类,而`List<Object>`却不是`List<T>`的父类**。 在解释为什么在Java中无法声明泛型数组之前,我们先来看一下Java泛型的实现方式。**Java中的泛型是类型擦除的,可以看作伪泛型,简单来说,就是你无法在程序运行时获取到一个对象的具体类型**。我们可以用以下代码来对比一下`List<T>`和数组: System.out.println(appleArray.getClass()); System.out.println(appleList.getClass()); // 运行结果 class [Ljavat.Apple; class java.util.ArrayList 从上面的代码我们可以知道,**数组在运行时是可以获取自身的类型,而`List<Apple>`在运行时只知道自己是一个List,而无法获取泛型参数的类型。而Java数组是协变的,也就是说任意的类A和B,若A是B的父类,则A[]也是B[]的父类。但是假如给数组加入泛型后,将无法满足数组协变的原则,因为在运行时无法知道数组的类型**。 Kotlin中的泛型机制与Java中是一样的,所以上面的特性在Kotlin中同样存在。比如通过下面的方式同样无法获取列表的类型: val appleList = ArrayList<Apple>() println(appleList.javaClass) 但不同的是,**Kotlin中的数组是支持泛型的,当然也不再协变,也就是说你不能将任意一个对象数组赋值给`Array<Any>`或者`Array<Any? >`**。在Kotlin中Any为所有类的父类,下面是一个例子: val appleArray = arrayOfNulls<Apple>(3) val anyArray: Array<Any? > = appleArray //不允许 我们已经知道了在Kotlin和Java中泛型是通过类型擦除来实现的,那么这又是为什么呢?