为啥这一行不编译 List<Object> l = new ArrayList<String>()? [复制]
Posted
技术标签:
【中文标题】为啥这一行不编译 List<Object> l = new ArrayList<String>()? [复制]【英文标题】:Why does this line not compile List<Object> l = new ArrayList<String>()? [duplicate]为什么这一行不编译 List<Object> l = new ArrayList<String>()? [复制] 【发布时间】:2018-05-19 05:08:50 【问题描述】:我希望能够列出这样的清单 -
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 做类似的事情,它可以编译但在 runtime 时抛出异常。
Object o[] = new String[10];
o[0] = new Dog();
那么允许后者代码编译但不允许前者编译的原因是什么?
编辑 - 类似的问题已经被问过,如上所述。 这个问题也有帮助Why is the ArrayStoreException a RuntimeException?
【问题讨论】:
为什么链接的问题没有回答您的问题?我的意思是它解释了为什么 Java 不支持这种语法。如果不是这样,您到底想达到什么目标?如果您编写new ArrayList<String>()
,该列表将仅接受 String
及其子类型。如果你改为写new ArrayList<Object>()
,你可以添加所有你想要的。
你是说你宁愿在运行时出现异常而不是编译错误?这似乎没有多大意义。
不,我不是这么说的。我只是问这背后的原因是什么。
嗯,泛型的全部意义在于避免运行时异常,所以……你还需要什么其他理由?
我需要解释为什么数组允许同样的事情,在这种情况下为什么不编译时错误?基本上我要问的是为什么我们有这个双重政策,一个针对数组,另一个针对通用数组列表?
【参考方案1】:
正如您的链接所说,像这样定义您的List
:
List<? extends Object> l = new ArrayList<String>();
编辑
是的,原因
List<? extends Object> l = new ArrayList<String>(); l.add("asda");
不起作用是为了避免运行时异常,因为列表的类型可能是任何扩展 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
的子类,但它可能与?
的类型不同(在这种情况下也不是)。
也不要忘记泛型类型在运行时因为类型擦除而消失了。泛型是编译时的保证。
另外,现在我看到了你真正的问题。
我需要解释为什么数组允许同样的事情,在这种情况下为什么不编译时错误?基本上我要问的是为什么我们有这个双重政策,一个针对数组,另一个针对通用数组列表?
查看this问题及其相关答案
【讨论】:
List<? extends Object> l = new ArrayList<String>();
l.add("asda");
还是不行。【参考方案2】:
你可以写
List<Object> l = new ArrayList<Object>();
类型参数只在编译时存在,所以这没什么区别。
【讨论】:
以上是关于为啥这一行不编译 List<Object> l = new ArrayList<String>()? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能从 List<MyClass> 转换为 List<object>?
如何将 List<Object> 转换为 List<MyClass>