列表与列表<对象>?</对象>

时间:2014-02-20 15:14:33

标签: java collections

请说明List - 原始类型与List<Object>之间的区别。

以下代码给出了运行时错误:

public static void main(String[] args) {
    List<String> strings = new ArrayList<String>();
    unsafeAdd(strings, new Integer(42));
    String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
    list.add(o);
}

这会产生编译时错误:

public static void main(String[] args) {
    List<String> strings = new ArrayList<String>();
    unsafeAdd(strings, new Integer(42));
    String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List<Object> list, Object o) {
    list.add(o);
}

5 个答案:

答案 0 :(得分:7)

在第二种情况下,你正在做一些编译器可以锻炼的东西并不安全。在第一种情况下,您使用的是原始类型,因此编译器不会执行相同的检查。

答案 1 :(得分:2)

Java没有参数类型的继承。因此List<Integer>不是List<Object>的子类,因此您无法使用List<Integer>List<String>作为unsafeAdd方法的参数。但你可以写:

private static <T> void unsafeAdd(List<T> list, T o) {
     list.add(o);
}

和safelly称之为:

List<String> strings = ...
unsafeAdd(string, "42");

并在以下情况下收到错误:

List<String> strings = ...
unsafeAdd(strings, 42); // error!

您可以在Oracle Generics Tutorial, Generics, Inheritance, and Subtypes

中查看更多信息

答案 2 :(得分:0)

在第一种情况下,您将未参数化的List传递给unsafeAdd,因此编译器无法弄清楚出错的地方。

List<String>传递给期望List的方法即可。将对象添加到List是可以的。

在第二种情况下,您将List<String>传递给期望List<Object>的方法 - 这不是正常的。因为这种方式暗示允许将非String添加到List<String> - 编译器可以在这种情况下解决它并引发错误。

答案 3 :(得分:0)

正如彼得已经说过的那样,在第一个例子中,你告诉编译器使用原始类型,因此不对列表执行任何检查。因此,它允许您将任何对象添加到传递的列表中,即使它被定义为仅允许字符串。

在第二个示例中,您告诉编译器它应该假定列表允许任何对象,因此add操作将编译。但是,不允许将List<String>作为List<Object>传递,因为字符串列表具有比仅作为对象的内容更具体的限制,因此编译器知道这是不安全且容易出错的。 / p>

如果您将参数定义为List<? extends Object> list,编译器会接受传递List<String>,因为您告诉它最小要求是列表必须接受对象,但它也可能施加更严格的约束。但是,add操作现在不会编译,因为编译器不知道 if 是否存在更严格的约束,如果是,那么这些约束是什么。因此,它无法确保添加操作是安全的并且拒绝编译该行。

答案 4 :(得分:0)

然而它看起来是一样的,它不是。

List(原始类型)并不关心你插入的内容。

List<String>List<Object>不兼容。你可以这样做:

String s = "Hello";
Object o = s;

但你不能这样做:

List<String> ls = ...;
List<Object> lo = ls; // Compilation error!

您的示例是一个很好的例证为什么 Java语言不允许它。通过允许这样的分配,恶意方法可以将任何内容放入客户端认为是字符串列表的列表中。

请考虑以下代码:

public void method changeObject(Object o) {
    o = 42;
}
public void method changeList(List<Object> lo) {
    lo.add(42);
}
...
String str = "Hello";
changeObject(str);
// Here it is still safe to use str, its value has not been modified
String str2 = str; // OK

List<String> list = new ArrayList<>();
changeList(list); // it is not allowed, but let's assume it is
// here the list variable would violate its contract - everybody has a right 
// to expect it is a list of Strings
String str3 = list.get(0); // Ouch! :(