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

Java 列表与列表<;对象>;,java,generics,Java,Generics,为什么我们在使用List时会失去类型安全性,而在使用List时却不会?它们基本上不是一回事吗 编辑:我发现下面给出了一个编译错误 public class TestClass { static void func(List<Object> o, Object s){ o.add(s); } public static void main(String[] args){ func(new ArrayList<String&

为什么我们在使用
List
时会失去类型安全性,而在使用
List
时却不会?它们基本上不是一回事吗

编辑:我发现下面给出了一个编译错误

public class TestClass
{
    static void func(List<Object> o, Object s){
        o.add(s);
    }

    public static void main(String[] args){
        func(new ArrayList<String>(), new Integer(1));
    }
}
公共类TestClass
{
静态无效函数(列表o,对象s){
o、 添加(s);
}
公共静态void main(字符串[]args){
func(新的ArrayList(),新的整数(1));
}
}
而这并不是

public class TestClass
{
    static void func(List o, Object s){
        o.add(s);
    }

    public static void main(String[] args){
        func(new ArrayList<String>(), new Integer(1));
    }
}
公共类TestClass
{
静态无效函数(列表o,对象s){
o、 添加(s);
}
公共静态void main(字符串[]args){
func(新的ArrayList(),新的整数(1));
}
}

为什么?

在这里,你可以说它们是一样的东西。但想必您几乎从来没有用
对象
的纯实例来填充
列表
。它们是
String
s之类的东西。在本例中,
List
在技术上使用泛型,但并没有真正利用它。因此,它会丢失泛型的编译时类型检查。

当您使用
List
而不是
List
时,出现编译器警告的原因是,当您有
List
时,编译器不知道它是什么类型的列表,因此尽管您可以将其视为
List
,但是,编译器无法确保在代码中的某个其他点它没有被设置为引用
列表
,并且无法检查泛型的类型安全性。这确实是编译器的警告——它说这无助于确保泛型的类型安全,而且也不会在运行时发生(直到稍后代码中出现实际的强制转换)

为什么我们在使用
List
时会失去类型安全性,而在使用
List
时却不会?它们基本上不是一回事吗

不,它们不是一回事

如果您提供的是API

class API {
  static List<Object> getList() { ... }
  static void modifyList(List<Object> l) { ... }
}

所以

func(new List<String>(), "");
func(新列表(),“”);
会有用的


这违反了类型安全。执行此操作的类型安全方法是

<T> void func(List<? super T> s, T c) { s.add(c); }
void func(ListA
List
实际上并不比
List
更安全。然而,代码中的
对象
确实暗示了意图。当其他人稍后查看它时,他们会看到你故意选择了
对象
作为类型,而不是怀疑你是否只是忘记了放置类型或正在存储其他内容和数据。)在别处打字


由于代码读得比写得多,因此提示代码的意图在以后可能非常有价值。

列表是一个您不知道的某种类型的列表。它可能是一个
列表
列表
,等等。

它实际上相当于
List
,或者
List类型擦除是一个答案,它向后兼容Java 1.5之前的版本,并且在第一个版本中进行更严格的类型检查

Java语言中引入了泛型,以在编译时提供更严格的类型检查,并支持泛型编程。为了实现泛型,Java编译器将类型擦除应用于:

如果类型参数是无界的,则用其边界或对象替换泛型类型中的所有类型参数。因此,生成的字节码仅包含普通类、接口和方法。 如有必要,插入类型强制转换以保持类型安全。 生成桥接方法以在扩展泛型类型中保留多态性。
类型擦除确保不会为参数化类型创建新类;因此,泛型不会产生运行时开销。

是的,我发现了类似的情况。当我有以下情况时,程序不会编译:
func(List s,Object c){s.add(c)}
并调用
func(new ArrayList(),new Integer(1));
。当我将方法更改为
func(List s,Object o)
并以相同的方式再次调用它时,如果没有泛型类型,for循环也不会编译。@Varun,
List
不是
List
,因为
myList.add(Boolean.FALSE)
myList
List
时有效,但在
List
时无效。也许您的函数应该是
void func(List“执行此操作的类型安全方法是…”只需说
void func(List s,tc){s.add(c);}
@user102008,对。但这并不是一般性的。然后不能执行
列出异构列表=…;func(异构列表,“foo”);
,因为
“foo”
使
T
绑定到该调用站点的
String
,但是
hetergeneousList
有一种
List
类型,它不是
列表
。如果我试图尽可能地笼统,我可能应该使用
集合
,而不是
列表
。直接回答为什么第二种编译方式是,在Java5之前编写的代码可以由Java5或更高版本编译。
void func(List s, Object c) { s.add(c); }
func(new List<String>(), "");
<T> void func(List<? super T> s, T c) { s.add(c); }