为什么List<Number>不是List<Object>的子类型? 在Java中,
String
不是Object
的子类型吗?那么,为什么我不能将类型为
List<String>
的对象传递给接受List<Object>
作为参数的函数呢?但是,我可以将这样的对象传递给接受List
作为参数的函数。String
不是Object
的子类型吗?List<String>
的对象传递给接受List<Object>
作为参数的函数呢?但是,我可以将这样的对象传递给接受List
作为参数的函数。String在Java中不是Object的子类型吗?
是的,但这并不意味着List<String>
是List<Object>
的子类型。
考虑以下示例:
List<String> l1 = new ArrayList<String>();
List<Object> l2 = l1; // This is a compilation error in real Java
l2.add(new Integer(42));
String oops = l1.get(0);
如果(假设)List<String>
是 List<Object>
的子类型,那么在最后一条语句中,您将会把一个Integer
分配给 String
变量。总之,这会破坏静态类型安全。
不过,我可以将这样的对象传递给接受
List
参数的函数。
是的,没错。但是您现在处理的是原始类型,并且在从列表中取出对象时需要使用显式类型转换。例如,上面的代码需要重写为以下形式:
List<String> l1 = new ArrayList<String>();
List l2 = l1;
l2.add(new Integer(42));
String oops = (String) l1.get(0);
请注意,类型转换意味着我们不得不用运行时类型安全性来代替静态类型安全性。(当然,在这种情况下,类型转换会在运行时失败,因为实例的类型错误。)
在给定的 List<T>
中,T
是参数化类型。
List<String>
与 List<Object>
没有任何关系,就像 List<String>
与 List<Number>
没有任何关系一样。 类型
是 List<String>
,整个签名就是 类型
。但是像所有事物一样,也存在例外;这些被称为 通配符参数化类型
。
List<?>
被称为 无限制通配符参数化类型,它的工作方式几乎与原始类型相同,它们在语义上相同,但会导致更多有关不安全转换的编译器警告。
List<? extends Object>
是一个有界通配符参数化类型,它允许你放置任何 extends Object
的东西,但由于 Java 中的每个类都 extends Object
,所以它在语义上与前两个选项没有任何区别。
现在它们都会执行相同的功能,但它们将无法通过 instanceof
测试,它们不是相同的类型。
换句话说:
public void myfunction(final List<Object> list) {}
只接受 List<Object>
类型,List
和 List<?>
与 List<Object>
的类型无关,尽管它们在语义上具有相同的功能。
type
可以是 List
、List<Object>
或 List<String>
,但在考虑 List<T>
的类型时,不会考虑 <>
中的继承链,直到涉及 Wild Card Parameterized Types。
以下是示例:
Collection<?> coll = new ArrayList<String>();
List<? extends Number> list = new ArrayList<Long>();
new Collection<?>
,只能给它分配一个具体的实现。
List<Object>
是整个类型。List
和 List<?>
可以互换使用吗? - dangerChihuahua007List
是一个原始类型,您可以从中添加/获取任何类型的 Object
。List <?>
是一个未知对象的集合,因此您可以从中获取 Object
,但不能向其中添加任何内容。 - JeffreyList<?> wl = whatever(); wl.add(new Object())
将失败,但如果使用原始类型,则会编译并发出警告。因此,是的,List
和 List<?>
是可以互换的,但仅在与 List<Integer>
和 List<Crayon>
相同的意义上...也就是说,不是。 - yshavitList<S>
不是 List<T>
的子类型。这个规则提供了类型安全性。List<String>
成为List<Object>
的子类型。考虑以下例子:public void foo(List<Object> objects) {
objects.add(new Integer(42));
}
List<String> strings = new ArrayList<String>();
strings.add("my string");
foo(strings); // this is not allow in java
// now strings has a string and an integer!
// what would happen if we do the following...??
String myString = strings.get(1);
class MyCollection<T> {
public void addAll(Collection<T> otherCollection) {
...
}
}
T
集合,您想从另一个集合中添加所有项目。您不能为T
类型的子类型S
调用此方法,例如Collection<S>
。理想情况下,这是可以接受的,因为您只向您的集合添加元素,而不会修改参数集合。class MyCollection<T> {
// Now we allow all types S that are a subtype of T
public void addAll(Collection<? extends T> otherCollection) {
...
otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T)
}
}
List<? extends T>
(这意味着接受任何 T 子类,包括 T 本身),在这种情况下,List<? extends Object>
应该可以工作,但是 List<Object>
只限于以 Object 为模板的列表。
(A <: B) => (List<A> <: List<B>)
,其中<:
被解读为“是子类型”,而=>
被解读为“意味着”。)而且,只有在该列表是不可变的情况下才可能实现。 - missingfaktor