ArrayList<A> arrayList = new ArrayList<>();
arrayList.add(new A());
ArrayList arrayList2 = arrayList;
ArrayList<B> arrayList3 = arrayList2;
arrayList3.add(new B());
上面这段代码会向同一个ArrayList中添加两种不同的类型(A,B没有任何关系,是完全独立的两个类)。你也许会说正常没人这么写代码,但真正的代码可能会和他差异很大,最终出现问题的原因却和这里一致。
由于擦除的存在,如果你可以拿到ArrayList的泛型信息,arrayList,arrayList2,arrayList3会给你不同的答案。下面再举一个例子:
ArrayList arrayList = new ArrayList<Integer>();
上面这段代码,如果你获取到arrayList的泛型,你会发现,它不是Integer。
小结
由于“擦除”的存在,泛型类不存在向上转型,向下转型。特别的,当你“向上转型”到通用类型(如ArrayList<Integer> -> ArrayList)时,泛型会丢失,此时你会失去ArrayList中存储数据的类型的信息(此时ArrayList会丢失所有基于泛型的特性,它看起来就是一个没有泛型的ArrayList)。此时你可以“向下转型”到任何类型。
泛型只和声明点有关,没有实际类型一说。(普通的对象,当它被new出来,它的实际类型是确定的,无论你怎么转型,它本质上就是new时的类型,但泛型对象不是,泛型对象的泛型永远和声明点同类型,而不在乎new时的类型)