我希望能够像这样制作一个列表 -
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?
答案 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
。即使String
是Object
的子类,它也可能不是(并且在这种情况下)与?
的类型相同。
同样不要忘记,由于Type Erasure,泛型类型在运行时已经消失。泛型是编译时保证。
此外,现在我看到了你的真实问题。
我需要为什么同样的事情允许Arrays的原因,为什么不编译时间错误?基本上我要问的是为什么我们有这个双重策略,一个用于数组,一个用于通用ArrayLists的不同策略?
请参阅this问题及其相关答案
答案 1 :(得分:0)
你可以写
List<Object> l = new ArrayList<Object>();
类型参数仅在编译时存在,因此没有区别。