Java 列表与列表<;对象>;?

Java 列表与列表<;对象>;?,java,collections,Java,Collections,请解释列表-原始类型和列表之间的区别 下面的代码给出了运行时错误: 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 st

请解释
列表
-原始类型和
列表
之间的区别

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

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);
}
publicstaticvoidmain(字符串[]args){
列表字符串=新的ArrayList();
unsafeAdd(字符串,新整数(42));
String s=strings.get(0);//编译器生成的强制转换
}
私有静态void unsafeAdd(列表,对象o){
列表。添加(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 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);
}
publicstaticvoidmain(字符串[]args){
列表字符串=新的ArrayList();
unsafeAdd(字符串,新整数(42));
String s=strings.get(0);//编译器生成的强制转换
}
私有静态void unsafeAdd(列表,对象o){
列表。添加(o);
}

在第二种情况下,您正在做一些编译器可能会认为不安全的事情。在第一种情况下,您使用的是原始类型,因此编译器不会执行相同的检查。

Java没有参数类型的继承。因此
List
不是
List
的子类,因此不能将
List
List
用作
unsafeAdd
方法的参数。但你可以写:

private static <T> void unsafeAdd(List<T> list, T o) {
     list.add(o);
}
private static void unsafeAdd(列表,to){
列表。添加(o);
}
安全地称之为:

List<String> strings = ...
unsafeAdd(string, "42");
列表字符串=。。。
unsafeAdd(字符串,“42”);
并在以下情况下获取错误:

List<String> strings = ...
unsafeAdd(strings, 42); // error!
列表字符串=。。。
unsafeAdd(strings,42);//错误!

您可以在

中看到更多信息,在第一种情况下,您将unparametrized List传递给unsafeAdd,因此编译器无法找出错误

List
传递给期望
List
的方法是可以的。将对象添加到
列表中是可以的


在第二种情况下,您将
List
传递给需要
List
的方法,但这并不正确。因为这种方式隐含地允许将非字符串添加到
列表中
,所以编译器可以在这种情况下找到它并引发错误。

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

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


如果您将参数定义为
List,但它看起来是一样的,则它不是

列表
(原始类型)不关心插入的内容

列表
列表
不兼容。您可以这样做:

String s = "Hello";
Object o = s;
但你不能这样做:

List<String> ls = ...;
List<Object> lo = ls; // Compilation error!
列表ls=。。。;
列表lo=ls;//编译错误!
您的示例很好地说明了为什么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! :(
public void方法changeObject(对象o){
o=42;
}
公共作废方法变更列表(列表lo){
添加(42);
}
...
String str=“Hello”;
改变对象(str);
//在这里使用str仍然是安全的,它的值没有被修改
字符串str2=str;//好啊
列表=新的ArrayList();
变更列表(列表);//这是不允许的,但我们假设它是允许的
//在这里,list变量将违反其约定-每个人都有权
//期望它是一个字符串列表
String str3=list.get(0);//哎哟(

读取编译器错误。在编译时,
列表
不是
列表
。您不明白什么?
并安全地调用它。
-在这种情况下,方法名
unsafeAdd
会产生误导;)是的,当然,但我只是从问题代码中复制了这个名称。