通用限制地狱:绑定不匹配

我正在开发一个具有广泛的genericsinheritance和依赖树的项目。 转到编辑以查看更好的示例。 基础知识看起来像这样:

class A { ... } class B { ... } class C extends B { ... } class D extends A { ... } class StringMap { HashMap _elements; ... } 

所以现在我要编写一个包含特定StringMap类型的类。

 class X { StringMap<D> _thing = new StringMap<D>; ... } 

到目前为止,一切正常。 D实际上是一个非常长的名称,并且特定组合将在代码的其他部分中非常频繁地出现,因此我决定使用特定组合的类,以便更清楚并且具有更短的名称。

 class DC extends D { } //and go to update X class X { StringMap<D> _thing = new StringMap<D>(); //still works fine StringMap _thing = new StringMap(); //error ... } 

Eclipse给出了错误

绑定不匹配:类型DC不是StringMap类型的有界参数的有效替代

所以问题是,为什么这不仅仅起作用? DC什么都不做,只是扩展D并回应构造函数。 为什么StringMap看到DC不同,只是它只是一个它除外的子类?

编辑:
好的,重新设计的例子更接近我实际做的事情。 我测试了它确实产生了错误。 我在这里做的是使用generics类型来确保clone()为inheritance树中实现它的人返回正确的类。 然后在子类中,我使用B<T extends B>来确保B的子类在B的子类中作为generics类型T传递。

 public abstract class Undoable implements Comparable { public abstract T clone(); public abstract void updateFields(T modified); } abstract public class A<T extends A, U extends Comparable> extends Undoable { abstract U getKey(); @Override public int compareTo(T element) { return getKey().compareTo(element.getKey()); } } public class B<T extends B> extends A { @Override public T clone() { // TODO Auto-generated method stub return null; } @Override public void updateFields(T modified) { // TODO Auto-generated method stub } @Override String getKey() { // TODO Auto-generated method stub return null; } } public class C extends B { } public class D<T extends B> extends A<D, String> { @Override String getKey() { // TODO Auto-generated method stub return null; } @Override public D clone() { // TODO Auto-generated method stub return null; } @Override public void updateFields(D modified) { // TODO Auto-generated method stub } } public class DC extends D { } public class StringMap<T extends Undoable> { HashMap _elements; } public class Main { public static void main(String[] args) { StringMap<D> _thing = new StringMap<D>(); //works StringMap _thing1 = new StringMap(); //error //Bound mismatch: The type DC is not a valid substitute for //the bounded parameter <T extends Undoable> of the type StringMap } } 

你必须做错其他的事情,因为以下工作正常:

 import java.util.HashMap; public class Q { class A { } class B { } class C extends B { } class D extends A { } class StringMap { HashMap _elements; } class DC extends D { } //and go to update X class X { StringMap> thing1 = new StringMap>(); // still works fine StringMap thing2 = new StringMap(); // NO error!!! } } 

试着发布这样一个类来重现你的错误。

如上所述,您的代码没问题,但如果我能猜到,您打算编写以下行,这确实会导致错误:

 StringMap> _thing = new StringMap; //error 

原因与导致以下问题的原因相同:

 ArrayList = new ArrayList(); 

在定义标识符的类型时,即在左值中,给予类的generics类型参数不能被实例化,即在rvalue中,由其参数inheritance左值中给定的参数的类型实例化。 如果参数不同,则类型不被认为是兼容的,即使它们应该是直观的(如果在语言中实现generics有点不同)。

这有点儿了……

我不确定你为什么要这样做以及你想要使用StringMap的确切原因,但是将StringMap定义改为此将允许你完成编译的工作:

 class StringMap> { HashMap _elements; } 

这意味着类型T必须是任何类型的Undoable,只要该类型是T的逆变量(实际上是T本身)。 所以现在你可以这样做:

 StringMap _thing1 = new StringMap(); // no more error _thing1._elements.put("a key", new DC()); 

话虽如此,这只是一个理论上的练习 – 我强烈建议您避免使用这种复杂的inheritance层次结构,但如果没有完整的用例,很难提出替代方案。

我希望有所帮助!

嗯。 我希望这不是古老的,但我正在解决我也遇到的问题。 我注意到在D中, D必须扩展BC必须延伸D由于A中的循环 ,足以让我付出一大堆努力让没有人注意到。 问题出在StringMap类中,它严格地希望自己的输入扩展generics类,其generics必须是它的输入。

D有效,因为D与扩展中提到的类相同。 它是安全的。 D指自己。 D扩展A,String>。 使用它创建一个StringMap很好,因为D实现了Undoable>因为D扩展了A,String>,它扩展了Undoable>。 另一方面,DC还必须实现Undoable,这是不可能的,因为它只能扩展D; 一个解决方案可能是它还可以实现Undoable,其中需要使用DC的方法的新定义才能工作。 这是您遇到的真正问题。 我希望这能解决你的问题。

我的老问题:

在D类中,T延伸B,但随后D延伸A>。 但是,它不是返回预期的A或A>,而是扩展A,String>。 但是, D不会延长B. 因此,无论是A,String>还是A.由于inheritance自两个具有不同通用封闭类的相同接口并未在Java中实现,因此T必须扩展D.但是, C不会扩展D ,这是您遇到的问题 ,是您将来可能需要解决的问题。