我正在努力寻找合适的措词来回答我的问题(这可能就是为什么我无法使用Google),但归结为:为什么下面的行无效?
List<AbstractInst<? extends IInstType>> insts = new ArrayList<MIPSInst>();
我收到了一个编译时错误ArrayList<MIPSInst> cannot be converted to List<AbstractInst<? extends IInstType>>
。班级MIPSInst extends AbstractInst<MIPSInstType>
和班级MIPSInstType implements IInstType
。
我已经阅读了有关泛型的Oracle文档,但显然这里缺少一些关键之处。朝正确方向轻推将不胜感激!
今天早些时候,我认为您想List<? extends AbstractInst<? extendsIInstType>>
成为的数据类型insts
。当然,这是将与您创建的对象匹配的数据类型,但是我怀疑在这种情况下它是否真的是您想要的。请按要求进行解释。
假设您有一个扩展了另一个类的类,例如PrintWriter
extends Writer
。就是说,每个PrintWriter
也都是a
Writer
,但是还有一些额外的方法(例如println
),您可以使用type变量来调用PrintWriter
,但不能使用type变量来调用Writer
。(与标准相比,我更喜欢真实的示例Dog extends Animal
)。
重要的是要了解它ArrayList<PrintWriter>
不是的子类型ArrayList<Writer>
,尽管从直观上看可能不是。原因是这样的。假设我有一个变量myList
,并且写了myList.add(new StringWriter());
什么类型的myList
?显然不能是类型ArrayList<PrintWriter>
,因为a
StringWriter
不是a PrintWriter
。但是它 可能 是类型ArrayList<Writer>
,因为a
StringWriter
肯定是a Writer
,因此必须能够将其添加到中ArrayList<Writer>
。
因此,任何ArrayList<Writer>
行都可以正常工作
myList.add(new StringWriter());
但任何ArrayList<PrintWriter>
会 不会 。因此,从某种意义上来说,a
ArrayList<PrintWriter>
不可能是的特殊类型。ArrayList<Writer>``PrintWriter``Writer
换句话说,应该可以这样写
ArrayList<Writer> myList = new ArrayList<Writer>();
myList.add(new StringWriter());
但是编译器应该以某种方式阻止我们编写此代码
ArrayList<Writer> myList = new ArrayList<PrintWriter>();
myList.add(new StringWriter());
由于第二行显然可以,因此它必须是第一行会产生编译错误。事实上,这是-
你不能分配ArrayList<PrintWriter>
给类型的变量ArrayList<Writer>
,因为ArrayList<PrintWriter>
只是
不是 一个ArrayList<Writer>
。或如乔恩·斯基特(Jon
Skeet)在https://stackoverflow.com/a/2745301/1081110上所说的“Awooga awooga”。
尽管如此ArrayList<Writer>
,ArrayList<PrintWriter>
和ArrayList<StringWriter>
似乎都有些相似。似乎应该有某种类型的变量可以引用这三个变量中的任何一个。确实有-是ArrayList<? extends Writer>
。但这是一种 抽象类型 。您无法实例化它。您不能写new ArrayList<? extends Writer>()
-最终ArrayList<? extendsWriter>
必须实际上是一个ArrayList<Writer>
,一个ArrayList<PrintWriter>
或一个ArrayList<StringWriter>
(或可能是ArrayList
某种其他类型的Writer
)。
这对我们来说应该不会太打扰。毕竟List<Writer>
也是抽象类型。您无法编写文字new List<Writer>()
,因为a
List<Writer>
实际上必须是ArrayList<Writer>
或LinkedList<Writer>
或其他类型的列表Writer
。
另外,类型变量ArrayList<? extends Writer>
并不总是拥有最有用的变量,因为您不能使用它来向列表中添加内容。如果myList
是类型的ArrayList<? extends Writer>
,那么你就不能写myList.add(myWriter);
不论类型是什么myWriter
是,因为编译器无法检查的方式myWriter
是
正确 的排序Writer
的名单。
您可以使用类型变量ArrayList<? extends Writer>
来将事情从列表中删除。如果myList
是类型ArrayList<? extends Writer>
,则 可以 写
Writer myWriter = myList.get(0);
因为无论myList
指的是ArrayList<Writer>
an ArrayList<PrintWriter>
还是an
ArrayList<StringWriter>
,您都知道其中的含义是Writer
。
所以回到实际问题,你在哪里
List<AbstractInst<? extends IInstType>> insts = new ArrayList<MIPSInst>();
最初看来是合理的,因为正如您所解释的MIPSInst
,的确是的子类型AbstractInst<? extendsIInstType>
。或者换一种说法,每个MIPSInst
都是一个AbstractInst<? extends IInstType>
。
显然,您可能已经写过
List<MIPSInst> insts = new ArrayList<MIPSInst>();
并能够将内容添加到列表中,并从列表中删除内容。但是您想使用某种类型表达式来表明任何类型AbstractInst<? extendsIInstType>
都可以,并且您只会将该变量用于可以在任何类型List
的AbstractInst<? extendsIInstType>
对象上使用的东西。
正如我在示例中展示StringWriter / PrintWriter
的那样,您正在寻找的类型是List<? extends AbstractInst<? extends IInstType>>
。这封装了以下事实:该列表可以是List
任何类型的AbstractInst<?extends IInstType>
,包括MIPSInst
。
但是,除非您将此变量强制转换为其他变量,否则使用此类型将限制您使用列表的只读视图。您可以get
从列表中进行操作,但是却add
一无所获,因为编译器无法检查添加的类型是否正确AbstractInst<?extends IInstType>
。
在这种情况下,您将创建一个空列表。因此,引用可以让您get
填充但不能add
填充的引用可能不是很有用。因此,与我之前的评论相反,最好只是将变量声明为aList<MIPSInst>
,然后将所有add
事情都get
放在心上。
问题内容: 我有一个关于将子类列表分配给超类列表的基本问题。 所以我有以下内容: 为什么最后一次分配失败?对不起,新手问题 问题答案: 为了解释这一点,让我用整数代替“ B”,用数字代替“ A”。这只是为了使其更容易解释。 失败的原因是因为nList可以采用任何Number;可以采用Integer;可以采用Double;或者就此而言,可以是Number的任何子类。但是,对于iList并非如此。您不
问题内容: 据我所知,Java中泛型的主要目的之一是提供编译时类型安全性。如果它被编译,代码将运行没有问题。 那么为什么要编译以下代码? 它编译良好。我的类型安全编译在哪里?该方法与类没有任何共同之处。 问题答案: 这本质上不是类型擦除问题,而是几乎相反的情况:当系统知道实际类型时,就会在运行时遇到问题,而编译时却不会。编译的原因是那是一个接口。就编译器而言,的子类可能实际上实现了该接口,因此编译
我在使用map类时遇到了一个编译器问题,并编写了以下简单程序来突出显示错误: 我发现以下编译错误: g./test.cc./test.cc:在函数int main()': ./ test.cc:13: 23:错误:在testmap.std::映射中的操作符=的模糊重载 我有几个问题:1。起初,我认为映射“值”——11和22正在转换为字符串。然而,在得到这个编译器错误后,我却不这么认为。引擎盖下面到
以下代码: 给出编译器错误: 此行有多个标记-类型列表中的方法add(capture#1-of?extends String)不适用于参数(String)-方法add(capture#1-of?)类型列表中的不适用于参数(字符串) 是什么导致了这个错误?我应该不能添加Strings或它的子类型,因为我正在类型参数中扩展String吗?
问题内容: 我在项目中创建了一个工厂类,从理论上讲,该类允许我为任何(受支持的)给定类型创建管理器。与管理器进行交互使我可以更改给定类型的某些属性。我面临的问题是,当我尝试为泛型类型创建管理器时,编译器粉碎了我的希望和梦想。 以下代码是我正在使用的简化版本。我尝试创建“ test3Manager”的行将不会编译,并且我试图了解为什么会这样。它下面的线显示了一种“解决方法”,我正试图避免这种情况。
与有界通配符相关的编译器错误 应兼容的不兼容通配符类型