6

我正在开发一个具有广泛的通用继承和依赖关系树的项目。去编辑看看更好的例子。基本看起来像这样:

class A {
  ...
}

class B {
  ...
}

class C extends B {
  ...
}

class D<T extends B> extends A {
  ...
}

class StringMap<T extends A> {
   HashMap<String, T> _elements;
   ...
}

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

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

到目前为止,这一切都很好。D<C>实际上是一个很长的名字,具体的组合在代码的其他部分会经常出现,所以我决定为具体的组合创建一个类,这样它会更清晰,名字更短。

class DC extends D<C> {

}

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

Eclipse给出的错误

有界不匹配:该类型DC不是该类型的有界参数<T extends A>的有效替代品StringMap<T>

所以问题是,为什么这不起作用?除了扩展和回显构造函数DC之外什么都不做。当它只是它所排除的东西的子类时,D<C>为什么会StringMap看到不同?DC

编辑:
好的,修改了示例以更接近我实际在做的事情。我测试了它,它确实产生了错误。我在这里所做的是使用泛型类型来确保clone()为继承树中实现它的任何人返回正确的类。然后在子类中,我B<T extends B<T>>用来确保 的子B类将 B 的子类作为泛型类型传入T

public abstract class Undoable<T> implements Comparable<T> {
  public abstract T clone();
  public abstract void updateFields(T modified);
}

abstract public class A<T extends A<T, U>, U extends Comparable<U>>
    extends Undoable<T> {
  abstract U getKey();

  @Override
  public int compareTo(T element)
  {
    return getKey().compareTo(element.getKey());
  }
}

public class B<T extends B<T>> extends A<T, String> {
  @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<C> {

}

public class D<T extends B<T>> extends A<D<T>, String> {
  @Override
  String getKey()
  {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public D<T> clone()
  {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public void updateFields(D<T> modified)
  {
    // TODO Auto-generated method stub
  }
}

public class DC extends D<C> {

}

public class StringMap<T extends Undoable<T>> {
  HashMap<String, T> _elements;

}

public class Main {
  public static void main(String[] args)
  {
    StringMap<D<C>> _thing = new StringMap<D<C>>(); //works
    StringMap<DC> _thing1 = new StringMap<DC>(); //error
//Bound mismatch: The type DC is not a valid substitute for
//the bounded parameter <T extends Undoable<T>> of the type StringMap<T>

  }
}
4

4 回答 4

8

您一定做错了其他事情,因为以下工作正常:

import java.util.HashMap;

public class Q {
    class A {
    }
    class B {
    }
    class C extends B {
    }
    class D<T extends B> extends A {
    }

    class StringMap<T extends A> {
        HashMap<String, T> _elements;
    }

    class DC extends D<C> {

    }

    //and go to update X
    class X {
        StringMap<D<C>> thing1 = new StringMap<D<C>>(); // still works fine
        StringMap<DC> thing2 = new StringMap<DC>(); // NO error!!!
    }
}

尝试发布这样的类来重现您的错误。

于 2011-01-20T18:47:14.627 回答
4

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

StringMap<D<C>> _thing = new StringMap<DC>; //error

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

ArrayList<Number> = new ArrayList<Integer>();

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

这有点问题...

于 2011-01-20T19:01:12.920 回答
2

我不确定你为什么要这样做以及你想使用 StringMap 的确切用途,但是将 StringMap 定义更改为此将允许你所做的编译:

class StringMap<T extends Undoable<? super T>> {
  HashMap<String, T> _elements;
}

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

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

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

我希望这会有所帮助!

于 2011-01-28T13:38:24.257 回答
0

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

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

我的老问题:

在 D 类中,T 扩展了 B,但 D 扩展了 A>。但是,它没有返回预期的 A 或 A>,而是扩展了 A、String>。但是,D 不扩展 B。因此,A, String> 和 A。由于在 Java 中没有实现从具有不同泛型封闭类的两个相同接口的继承,因此 T 必须扩展 D。但是,C 不扩展 D ,这是您遇到的问题是您将来可能需要解决的问题。
于 2012-06-14T02:52:27.637 回答