java 泛型中的通配符
Wildcards in java Generics
我知道泛型是不变的:对于任何两种不同的类型 Type1 和 Type2,
List 既不是 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)
假设通配符是对象,那么第 2 行将是
List<Object> sink = List<Number> nums
这里似乎没有应用不变规则
谁能给我解释一下为什么第 2 行编译没有错误?
非常感谢
让我们有:
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
.
不变规则确实适用。声明:
List<? super Number> sink = nums;
只是行不通,你想的那样。
我希望你认为可以将ArrayList类型的对象赋值给List<? super Number>
类型的变量,因为前者是后者的子类。这将打破不变规则,但这不是正在发生的事情。
List<? super Number>
变量表示所有可能列表的集合,其中 someClass 是 Number 或者是 Number 的祖先。
let say if wildcard is Object so line 2 wil be
`List<Object> sink = List<Number> nums `
在这种情况下?不会被任意设置,所以这不会发生。
如果我没记错的话,你希望对下面的有效代码有一个解释:
List<Number> nums = new ArrayList<Number>();
List<? super Number> sink = nums;
不变性是 属性 的 class 关于其类型参数如何影响其子类型。
泛型是不变的,但通配符的存在可以帮助我们进行子类型化。它们不是很有用,因为它们不代表任何类型,但代表一个很好的 hack。以下有效
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。
我知道泛型是不变的:对于任何两种不同的类型 Type1 和 Type2,
List
所以
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)
假设通配符是对象,那么第 2 行将是
List<Object> sink = List<Number> nums
这里似乎没有应用不变规则
谁能给我解释一下为什么第 2 行编译没有错误?
非常感谢
让我们有:
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
.
不变规则确实适用。声明:
List<? super Number> sink = nums;
只是行不通,你想的那样。
我希望你认为可以将ArrayList类型的对象赋值给List<? super Number>
类型的变量,因为前者是后者的子类。这将打破不变规则,但这不是正在发生的事情。
List<? super Number>
变量表示所有可能列表的集合,其中 someClass 是 Number 或者是 Number 的祖先。
let say if wildcard is Object so line 2 wil be
`List<Object> sink = List<Number> nums `
在这种情况下?不会被任意设置,所以这不会发生。
如果我没记错的话,你希望对下面的有效代码有一个解释:
List<Number> nums = new ArrayList<Number>();
List<? super Number> sink = nums;
不变性是 属性 的 class 关于其类型参数如何影响其子类型。
泛型是不变的,但通配符的存在可以帮助我们进行子类型化。它们不是很有用,因为它们不代表任何类型,但代表一个很好的 hack。以下有效
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。