我正在开发一个具有广泛的泛型继承和依赖树的项目。转到编辑以查看更好的示例。 基础知识看起来像这样:
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>
}
}
答案 0 :(得分: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!!!
}
}
尝试发布这样一个类来重现你的错误。
答案 1 :(得分:4)
如前所述,您的代码没问题,但如果我能猜到,您打算写下面一行,这确实会导致错误:
StringMap<D<C>> _thing = new StringMap<DC>; //error
原因与导致以下问题的原因相同:
ArrayList<Number> = new ArrayList<Integer>();
在定义标识符的类型时给予类的泛型类型参数,即在左值,不能实例化,即在rvalue中,由参数继承的类型左值中给出的参数。如果参数不同,那么这些类型不会被认为是兼容的,即使它们应该是直观的(如果在语言中实现泛型有点不同)。
这有点儿了......
答案 2 :(得分: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());
话虽如此,这只是一个理论上的练习 - 我强烈建议您避免使用这种复杂的继承层次结构,但如果没有完整的用例,很难提出替代方案。
我希望有所帮助!
答案 3 :(得分:0)
嗯。我希望这不是古老的,但我正在解决我也遇到的问题。我注意到在D中, D必须扩展B 或 C必须扩展D ,因为A中的循环,足以让我放入一堆努力没有人注意到。问题出在StringMap类中,它严格地希望自己的输入扩展泛型类,其泛型必须是它的输入。
D有效,因为D与扩展中提到的类相同。它是安全的。 D指自己。 D扩展A,String&gt;。用它做一个StringMap很好,因为D实现了Undoable&gt;因为D扩展了A,String&gt ;,它扩展了Undoable&gt;。另一方面,DC也必须实现Undoable,这是不可能的,因为它只能扩展D;一个解决方案可能是它还可以实现Undoable,其中需要使用DC的方法的新定义才能工作。这是您遇到的真正问题。我希望这能解决你的问题。
我的老问题:
在D类中,T延伸B,但是D延伸A>。 但是,它不是返回预期的A或A&gt;而是扩展A,String&gt;。 但是, D不会延伸B 。因此,A,String&gt;由于继承自两个具有不同通用封闭类的相同接口并未在Java中实现,因此T必须扩展D.但是, C不会扩展D,这是你的问题遇到这是您将来可能需要解决的问题。