当类是通用的时,Java通配符奇怪的行为

前端之家收集整理的这篇文章主要介绍了当类是通用的时,Java通配符奇怪的行为前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我认为我对 Java泛型有一些很好的理解.

这段代码没有编译,我知道为什么.

我们只能传递给测试方法类型Animal的类型或它的超类型(如对象列表)

  1. package scjp.examples.generics.wildcards;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. class Animal {}
  7. class Mammal extends Animal {}
  8. class Dog extends Mammal {}
  9.  
  10. public class Test {
  11.  
  12. public void test(List<? super Animal> col) {
  13. col.add(new Animal());
  14. col.add(new Mammal());
  15. col.add(new Dog());
  16. }
  17.  
  18. public static void main(String[] args) {
  19. List<Animal> animalList = new ArrayList<Animal>();
  20. List<Mammal> mammalList = new ArrayList<Mammal>();
  21. List<Dog> dogList = new ArrayList<Dog>();
  22.  
  23. new Test().test(animalList);
  24. new Test().test(mammalList); // Error: The method test(List<? super Animal>) in the type Test is not applicable for the arguments (List<Mammal>)
  25. new Test().test(dogList); // Error: The method test(List<? super Animal>) in the type Test is not applicable for the arguments (List<Dog>)
  26.  
  27. Dog dog = dogList.get(0);
  28. }
  29. }

但这里有一个奇怪的部分(至少对我而言).

如果我们通过仅添加< T>来声明类Test是通用的,那么它就会编译!并抛出java.lang.ClassCastException:

  1. public class Test<T> {
  2. ...
  3. }

,

  1. Exception in thread "main" java.lang.ClassCastException: scjp.examples.generics.wildcards.Animal cannot be cast to scjp.examples.generics.wildcards.Dog

我的问题是为什么添加泛型类类型< T> (它没有在任何地方使用)导致类编译和更改通配符行为?

解决方法

表达式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,则应编写

  1. Test<?> test = makeTest();
  2. test.test(animalList);
  3. test.test(mammalList);
  4. test.test(dogList);

在再次发现编译错误时欢喜(或诅咒,就此而言).

猜你在找的Java相关文章