kah*_*fan 12 java extends subtype
这就是我所知道的:
Double
是子类型,Number
而List<Double>
不是子类型List<Number>
.List<Dog>
不是子类型,List<Animal>
因为你可以添加Cat
,List<Animal>
但你不能这样做List<Dog>
.List<? extends Number>
表示此列表可以存储Number类型的变量和Number子类型的变量.List<Double>
表示此列表可以存储Double类型的变量.如果上面的任何错误,请纠正我,然后是List<Double>
子类型List<? extends Number>
和为什么?
aio*_*obe 11
你的所有物品都是正确的.
Double
是子类型,Number
而List<Double>
不是子类型List<Number>
.
List<Dog>
不是子类型,List<Animal>
因为你可以添加Cat
,List<Animal>
但你不能这样做List<Dog>
.
那是对的.泛型不是协变的(但数组是!).以下是一些后续阅读:为什么数组是协变的但是泛型是不变的?
List<? extends Number>
表示此列表可以存储类型的Number
变量和子类型的变量Number
.List<Double>
表示此列表可以存储类型的变量Double
.
这是事实,但是List<Number>
和之间有一个重要的区别List<? extends Number>
.你可以认为List<? extends Number>
作为一个具体的列表Number
亚型(即一List<Double>
,List<Integer>
,List<Long>
,...)和List<Number>
一种能潜在地包含的混合列表Double
,Integer
...
至于你的最后一个问题:
是...
List<Double>
的子类型List<? extends Number>
是的,你可以拥有
List<Double> doubles = new ArrayList<>();
List<? extends Number> numbers = doubles;
Run Code Online (Sandbox Code Playgroud)
......为什么?
这就是定义子类型的方式.
至于动机,假设你有一个接受数字列表的方法.如果让参数具有类型List<Number>
,则无法将参数传递List<Double>
给它.(您的问题中的第二项解释了原因!)相反,您可以让参数具有类型List<? extends Number>
.既然List<Double>
是List<? extends Number>
它的子类型将会解决.
在运行时,List<T>
与(1)List<U>
相同List
.
但是,这将随着值类型的引入而改变(预计将在JDK 9或JDK 10版本中发布,而不是在2016年中期之前).由于Brian Goetz在此解释了许多限制因素,因此将不再List<T>
相同List<U>
:http://cr.openjdk.java.net/~briangoetz/valhalla/specialization.html
(1) - T
和U
以前的陈述中的类型不同
还应该添加几点
在运行时List<Double>
,List<? extends Number>
,List<?>
和List<Object>
都是相同的.通用参数根本不编译.所有使用泛型的魔法都是编译时的乐趣.这也意味着如果你有一个List
空的,你不知道泛型参数是什么!
尽量不要将泛型参数视为"子类型",泛型参数实际上意味着" 类使用泛型参数 ",因此在这种情况下" 列表使用数字 ".一个很好的例子就是HashMap源代码,如果你看看它的内部工作原理,它实际上是存储一个数组Entry
,并且所有条目都存储了键和值.当你看到泛型的更复杂的用途时,你偶尔会看到这种用法.
在List
泛型参数的情况下意味着列表存储该类型的对象,可能是对象永远不会存储泛型参数类型的对象!像这样:
public class DummyIterator<O> implements Iterator<O>{
public boolean hasNext() {
return false;
}
public O next() {
return null;
}
}
Run Code Online (Sandbox Code Playgroud)究竟List<? extends Number>
是什么意思?嗯,它与List<Number>
大多数用途几乎相同.请记住,虽然说?
你几乎都在说"我不关心这种类型",它在这种情况下表现出来:
List<Double> doubles = new ArrayList<Double>();
List<? extends Number> numbers = doubles;
numbers.add(new Double(1)); //COMPILE ERROR
Number num = numbers.get(0);
Run Code Online (Sandbox Code Playgroud)
所以我们不能添加Double
一个<? extends Number>
.但是对于这个例子:
List<Double> doubles = new ArrayList<Double>();
List<Number> numbers = doubles; //COMPILE ERROR
numbers.add(new Integer(1));
Number num = numbers.get(0);
Run Code Online (Sandbox Code Playgroud)
你不能分配List<Double>
到List<Number>
这是有道理的,你是专门告诉它,列出只使用数种
那么你应该在哪里使用?
?你真的可以说"我不关心通用参数",例如:
boolean equalListSizes(List<?> list1, List<?> list2) {
return list1.size() == list2.size();
}
Run Code Online (Sandbox Code Playgroud)
? extends Number
只有在不使用generic参数修改对象的情况下,才会使用格式类型.例如:
Number firstItem(List<? extends Number> list1) {
return list1.get(0);
}
Run Code Online (Sandbox Code Playgroud)而不是使用?
和? extends Number
格式尝试在类/方法上使用泛型,在大多数情况下,它使您的代码更具可读性!:
<T extends Number> T firstItem(List<T> list1) {
return list1.get(0);
}
Run Code Online (Sandbox Code Playgroud)
类:
class Animal{}
class Dog extends Animal{}
class AnimalHouse<A extends Animal> {
List<A> animalsInside = new ArrayList<A>();
void enterHouse(A animal){
animalsInside.add(A);
}
A leaveHouse() {
return animalsInside.remove(0);
}
}
AnimalHouse<Dog> ah = new AnimalHouse<Dog>();
ah.enterHouse(new Dog());
Dog rufus = ah.leaveHouse();
Run Code Online (Sandbox Code Playgroud)作为泛型的奖励思想,您还可以参数化方法以返回特定类.一个很好的例子是junit中的any()方法和空列表集合:
Dog rufus = Matchers.<Dog>any();
List<Dog> dogs = Collections.<Dog>emptyList();
Run Code Online (Sandbox Code Playgroud)
此语法允许您指定对象的返回类型.有时知道非常有用(使一些铸造多余)!