我认为我对
Java泛型有一些很好的理解.
这段代码没有编译,我知道为什么.
我们只能传递给测试方法类型Animal的类型或它的超类型(如对象列表)
- package scjp.examples.generics.wildcards;
- import java.util.ArrayList;
- import java.util.List;
- class Animal {}
- class Mammal extends Animal {}
- class Dog extends Mammal {}
- public class Test {
- public void test(List<? super Animal> col) {
- col.add(new Animal());
- col.add(new Mammal());
- col.add(new Dog());
- }
- public static void main(String[] args) {
- List<Animal> animalList = new ArrayList<Animal>();
- List<Mammal> mammalList = new ArrayList<Mammal>();
- List<Dog> dogList = new ArrayList<Dog>();
- new Test().test(animalList);
- new Test().test(mammalList); // Error: The method test(List<? super Animal>) in the type Test is not applicable for the arguments (List<Mammal>)
- new Test().test(dogList); // Error: The method test(List<? super Animal>) in the type Test is not applicable for the arguments (List<Dog>)
- Dog dog = dogList.get(0);
- }
- }
但这里有一个奇怪的部分(至少对我而言).
如果我们通过仅添加< T>来声明类Test是通用的,那么它就会编译!并抛出java.lang.ClassCastException:
- public class Test<T> {
- ...
- }
,
- Exception in thread "main" java.lang.ClassCastException: scjp.examples.generics.wildcards.Animal cannot be cast to scjp.examples.generics.wildcards.Dog
解决方法
表达式new Test()是原始类型. Java语言规范
defines原始类型的成员类型如下:
The type of a constructor (§8.8),instance method (§8.8,§9.4),or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.
列表的删除<?超级动物>是列表.
这个定义背后的基本原理可能是原始类型旨在作为从非泛型遗留代码使用泛型类型的手段,其中类型参数从不存在.它们没有设计,并且不是最佳的,没有指定类型参数;这就是通配符类型的用途,即如果编写的编译器合规性级别大于1.5,则应编写
- Test<?> test = makeTest();
- test.test(animalList);
- test.test(mammalList);
- test.test(dogList);
在再次发现编译错误时欢喜(或诅咒,就此而言).