将通用List分配给具体的ArrayList会导致编译时错误

我正在努力为我的问题找到适当的措辞(这可能是我无法谷歌的原因),但它归结为:为什么下面的行无效?

List<AbstractInst> insts = new ArrayList(); 

我得到一个编译时错误, ArrayList cannot be converted to List<AbstractInst> ArrayList cannot be converted to List<AbstractInst>MIPSInst extends AbstractInstMIPSInst extends AbstractInstMIPSInstType implements IInstType

我已经阅读了关于generics的Oracle文档 ,但我在这里显然遗漏了一些关键。 在正确的方向轻推将非常感谢!

今天早些时候,我以为你想要List> List> List>的数据类型。 它肯定是一种与您正在创建的对象相匹配的数据类型,但我怀疑它是否实际上是您想要的。 按顺序解释。

假设你有一个扩展另一个类的类,比如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不可能是特殊类型的ArrayListPrintWriter是一种特殊类型的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”中表达的那样。

ArrayListArrayListArrayListArrayList似乎都有些相似。 似乎应该有某种类型的变量可以引用这三种变量中的任何一种。 确实有 – 它的ArrayList ArrayList 。 但这是一种抽象类型 。 你无法实例化它。 你不能写new ArrayList() new ArrayList() – 最终是一个ArrayList ArrayList实际上必须是ArrayListArrayListArrayList (或者可能是某些其他类型WriterArrayList )。

这对我们来说不应该太令人不安。 毕竟, List也是一种抽象类型。 您不能编写new List() ,因为List实际上必须是ArrayList ,或LinkedList ,或者其他类型的Writer列表。

另外, ArrayList的变量类型ArrayList ArrayList并不总是最有用的变量,因为你不能用它来添加东西到列表中。 如果myList的类型为ArrayList ArrayList ,然后你不能写myList.add(myWriter); 无论myWriter的类型是什么,因为编译器无法检查myWriter是否是列表的正确类型的Writer

你可以用ArrayList的变量做什么ArrayList ArrayList是为了让事情脱离列表。 如果myList的类型为ArrayList ArrayList ,然后你就可以写了

 Writer myWriter = myList.get(0); 

因为无论myList是指ArrayList ,还是ArrayList还是ArrayList ,你都知道它里面有什么类型的Writer

所以回到实际的问题,你在哪里

 List> insts = new ArrayList(); 

最初似乎是合理的,因为,你已经解释过MIPSInst确实是AbstractInst一个子类型AbstractInst AbstractInst 。 换句话说,每个MIPSInst都是一个AbstractInst AbstractInst

显然,你可以写

 List insts = new ArrayList(); 

并且能够将内容添加到列表中,并从列表中获取内容。 但是你想使用一些表明任何类型的AbstractInst AbstractInst是没关系的,你只会将这个变量用于任何类型的AbstractInst List AbstractInst AbstractInst对象。

正如我在我的StringWriter / PrintWriter示例中所演示的那样,您要查找的类型是List> List> List> 。 这封装了这个列表可以是任何类型的AbstractInstList AbstractInst AbstractInst ,包括MIPSInst

但是,除非将此变量强制转换为其他类型,否则使用此类型将限制您进入列表的只读视图。 你可以从列表中get东西,但你根本无法add任何东西,因为编译器无法检查你是否正在添加正确类型的AbstractInst AbstractInst

在此特定实例中,您将创建一个空列表。 因此,对它进行引用可能不是很有用,它可以让你get东西,但不能add东西。 因此,与我之前的评论相反,如果你只是将你的变量声明为List ,然后add内容并get内心的内容,那么最好。