为什么这行不能编译List <object> l = new ArrayList <string>()?

时间:2017-12-05 13:54:12

标签: java list generics inheritance arraylist

我希望能够像这样制作一个列表 -

List<Object> l = new ArrayList<String>();

ArrayList的标准库实现不允许这样做。它给出了编译时错误。所以我正在编写自己的ArrayList

实现

到目前为止,我已尝试过这个 -

public class ArrayList<Y extends X> implements List<X> {...}
public class ArrayList<X super Y> implements List<X> {...}

不编译。

那么,如何编写一个ArrayList,我可以像上面提到的那样使用它?

List<Object> l = new ArrayList<String>();

人们已经指出了这篇文章  Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

但我仍然不明白。给出的理由是我们想要避免这样的情况 -

List<Object> l = new ArrayList<String>();
l.add(new Dog()); 

虽然这是有道理的,但是我可以用Java Arrays做类似的事情,它编译但抛出 运行时的异常。

Object o[] = new String[10];
o[0] = new Dog();

那么允许后一个代码编译而不是前者的原因是什么呢?

编辑 - 如上所述,已经提出了类似的问题。 这个问题也有助于Why is the ArrayStoreException a RuntimeException?

2 个答案:

答案 0 :(得分:2)

正如您的链接所说,定义您的List,如此:

List<? extends Object> l = new ArrayList<String>();

修改

是的,原因是

List<? extends Object> l = new ArrayList<String>(); l.add("asda");

不起作用是为了避免运行时异常,因为List的类型可以是扩展Object的任何内容,因此编译器会将其视为(可能是任何/未知的)。但是,如果您保留对原始文件的引用,您仍然可以编辑列表。

List<String> strList = new ArrayList<>();
List<? extends Object> objList = strList;
strList.add("asdf");
// Will return Strings that only have the Object interface
Object o = objList.get(0);

List<? extends Object>的目的只是为你的代码提供一个类型保证(在这种情况下某些类型扩展Object)并且由于泛型,编译器能够在编译时确保条件但它还需要确保您不违反原始列表。以下面的代码为例:

List<Integer> intList = new ArrayList<>();
List<? extends Object> objList = intList;
// compile error to protect the original list
objList.add("asdf");

因为objList的类型为?,所以您无法为其添加String。即使StringObject的子类,它也可能不是(并且在这种情况下)与?的类型相同。

同样不要忘记,由于Type Erasure,泛型类型在运行时已经消失。泛型是编译时保证。

此外,现在我看到了你的真实问题。

  

我需要为什么同样的事情允许Arrays的原因,为什么不编译时间错误?基本上我要问的是为什么我们有这个双重策略,一个用于数组,一个用于通用ArrayLists的不同策略?

请参阅this问题及其相关答案

答案 1 :(得分:0)

你可以写

List<Object> l = new ArrayList<Object>();

类型参数仅在编译时存在,因此没有区别。