我知道泛型是不变的:对于任何两种不同的类型Type1和Type2, 列表与LT;类型1>既不是List的子类型也不是超类型< 类型2>
所以
List<someObject> nums = new ArrayList<someObject>(); // this is correct
List<Object> nums = new ArrayList<subObject>(); // this is not correct
但是
List<Number> nums = new ArrayList<Number>();
List<? super Number> sink = nums; ????(line 2)
如果通配符是Object,那么第2行将是
List<Object> sink = List<Number> nums
似乎这里没有应用不变规则
有人可以向我解释为什么第2行编译没有错误吗?
非常感谢
答案 0 :(得分:2)
如果我没错,您希望对以下有效代码的解释如下:
List<Number> nums = new ArrayList<Number>();
List<? super Number> sink = nums;
Invariance是类的属性,它的类型参数如何影响其子类型。
泛型是不变的,但存在通配符以帮助我们进行子类型输入。它们不是很有用,因为它们不代表任何类型但代表一个好的黑客。以下是有效的
List<Animal> <: List<?>
List<?> <: List
更好的例子:
List<? super Animal> d1= new ArrayList<Animal>();
d1.add(new Animal());
d1.add(new Dog());
上述方法有效,因为d1
的类型为List<? super Animal>
。你可以想象add
函数的行为如下:
boolean add(? super Animal e);
因此,对于add
方法,您可以传递? super Animal
的子类型的任何变量。和
Animal <: ? super Animal
Dog <: ? super Animal
所以添加狗或动物作品。因此d1
充当一个列表,可以接受Animal
类型的任何参数或子类型。
同样,你也可以在下面。但从技术上讲,你无法在此列表中添加任何内容。如果java中存在某种类型,即每种类型的子类型,那么您可以正确地向其添加该类型的元素。没什么。
ArrayList<? extends Animal> d1 = new ArrayList<Animal>();
请查看此答案,了解更多info。
答案 1 :(得分:1)
不变规则确实适用。声明:
List<? super Number> sink = nums;
只是按照你的想法行事。
我希望您认为可以将ArrayList类型的对象分配给类型为List<? super Number>
的变量,因为前者是后者的子类。这会破坏不变规则,但这不是正在发生的事情。
List<? super Number>
变量表示所有可能的List的集合,其中someClass是Number或者是Number的祖先。
如果通配符是Object,那么第2行将是
`List<Object> sink = List<Number> nums `
在这种背景下?没有任意设置,所以这不会发生。
答案 2 :(得分:-1)
让我们:
List<Integer> li = new ArrayList<>();
List<Object> lo = new ArrayList<>();
l = lo;//not allowed
lo.add("string");
Integer i = li.get(0);//that is string there
这就是为什么你不能做这样的任务。我认为编译器不会直接分配new ArrayList<Integer>()
以外的现有变量li
。