将通用List分配给具体的ArrayList会导致编译时错误
我正在努力为我的问题找到适当的措辞(这可能是我无法谷歌的原因),但它归结为:为什么下面的行无效?
List<AbstractInst> insts = new ArrayList();
我得到一个编译时错误, ArrayList cannot be converted to List<AbstractInst>
ArrayList cannot be converted to List<AbstractInst>
。 MIPSInst extends AbstractInst
类MIPSInst extends AbstractInst
, MIPSInstType implements IInstType
。
我已经阅读了关于generics的Oracle文档 ,但我在这里显然遗漏了一些关键。 在正确的方向轻推将非常感谢!
今天早些时候,我以为你想要List extends AbstractInst extends IInstType>>
List extends AbstractInst extends IInstType>>
List extends AbstractInst extends IInstType>>
的数据类型。 它肯定是一种与您正在创建的对象相匹配的数据类型,但我怀疑它是否实际上是您想要的。 按顺序解释。
假设你有一个扩展另一个类的类,比如PrintWriter
扩展了Writer
。 也就是说,每个PrintWriter
也是一个Writer
,但是有一些额外的方法(比如println
)可以使用PrintWriter
类型的变量调用,但不能使用Writer
类型的变量调用。 (我更喜欢标准Dog extends Animal
真实例子)。
重要的是要理解ArrayList
不是ArrayList
的子类型,尽管看起来可能是直观的。 原因是这个。 假设我有一个变量myList
,我写了myList.add(new StringWriter());
myList
可以是什么类型的? 它显然不能是ArrayList
类型,因为StringWriter
不是PrintWriter
。 但它可能是ArrayList
类型,因为StringWriter
绝对是一个Writer
,因此必须能够添加到ArrayList
。
因此,任何ArrayList
都可以在行中正常工作
myList.add(new StringWriter());
但任何ArrayList
都不会 。 因此, ArrayList
不可能是特殊类型的ArrayList
, PrintWriter
是一种特殊类型的Writer
。
换句话说,应该可以写这个
ArrayList myList = new ArrayList (); myList.add(new StringWriter());
然而编译器应该以某种方式阻止我们写这个
ArrayList myList = new ArrayList(); myList.add(new StringWriter());
由于第二行显然是正常的,因此它必须是生成编译错误的第一行。 实际上它是 – 你不能将ArrayList
分配给ArrayList
类型的变量,因为ArrayList
不是 ArrayList
。 或者正如Jon Skeet在https://stackoverflow.com/a/2745301/1081110,“Awooga awooga”中表达的那样。
ArrayList
, ArrayList
, ArrayList
和ArrayList
似乎都有些相似。 似乎应该有某种类型的变量可以引用这三种变量中的任何一种。 确实有 – 它的ArrayList extends Writer>
ArrayList extends Writer>
。 但这是一种抽象类型 。 你无法实例化它。 你不能写new ArrayList extends Writer>()
new ArrayList extends Writer>()
– 最终是一个ArrayList extends Writer>
ArrayList extends Writer>
实际上必须是ArrayList
, ArrayList
或ArrayList
(或者可能是某些其他类型Writer
的ArrayList
)。
这对我们来说不应该太令人不安。 毕竟, List
也是一种抽象类型。 您不能编写new List
,因为List
实际上必须是ArrayList
,或LinkedList
,或者其他类型的Writer
列表。
另外, ArrayList extends Writer>
的变量类型ArrayList extends Writer>
ArrayList extends Writer>
并不总是最有用的变量,因为你不能用它来添加东西到列表中。 如果myList
的类型为ArrayList extends Writer>
ArrayList extends Writer>
,然后你不能写myList.add(myWriter);
无论myWriter
的类型是什么,因为编译器无法检查myWriter
是否是列表的正确类型的Writer
。
你可以用ArrayList extends Writer>
的变量做什么ArrayList extends Writer>
ArrayList extends Writer>
是为了让事情脱离列表。 如果myList
的类型为ArrayList extends Writer>
ArrayList extends Writer>
,然后你就可以写了
Writer myWriter = myList.get(0);
因为无论myList
是指ArrayList
,还是ArrayList
还是ArrayList
,你都知道它里面有什么类型的Writer
。
所以回到实际的问题,你在哪里
List> insts = new ArrayList();
最初似乎是合理的,因为,你已经解释过MIPSInst
确实是AbstractInst extends IInstType>
一个子类型AbstractInst extends IInstType>
AbstractInst extends IInstType>
。 换句话说,每个MIPSInst
都是一个AbstractInst extends IInstType>
AbstractInst extends IInstType>
。
显然,你可以写
List insts = new ArrayList ();
并且能够将内容添加到列表中,并从列表中获取内容。 但是你想使用一些表明任何类型的AbstractInst extends IInstType>
AbstractInst extends IInstType>
是没关系的,你只会将这个变量用于任何类型的AbstractInst extends IInstType>
List
AbstractInst extends IInstType>
AbstractInst extends IInstType>
对象。
正如我在我的StringWriter / PrintWriter
示例中所演示的那样,您要查找的类型是List extends AbstractInst extends IInstType>>
List extends AbstractInst extends IInstType>>
List extends AbstractInst extends IInstType>>
。 这封装了这个列表可以是任何类型的AbstractInst extends IInstType>
的List
AbstractInst extends IInstType>
AbstractInst extends IInstType>
,包括MIPSInst
。
但是,除非将此变量强制转换为其他类型,否则使用此类型将限制您进入列表的只读视图。 你可以从列表中get
东西,但你根本无法add
任何东西,因为编译器无法检查你是否正在添加正确类型的AbstractInst extends IInstType>
AbstractInst extends IInstType>
。
在此特定实例中,您将创建一个空列表。 因此,对它进行引用可能不是很有用,它可以让你get
东西,但不能add
东西。 因此,与我之前的评论相反,如果你只是将你的变量声明为List
,然后add
内容并get
内心的内容,那么最好。