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

发布于 2024-10-13 05:27:27 字数 3196 浏览 9 评论 0 原文

我正在开发一个具有广泛的通用继承和依赖关系树的项目。去编辑查看更好的例子。 基础知识如下所示:

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 实际上是一个很长的名称,并且特定组合会在代码的其他部分中频繁出现,因此我决定为特定组合创建一个类,这样会更清晰并有一个更短的名字。

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 不能有效替代类型 StringMap 的有界参数 代码>

因此问题是,为什么这不起作用? DC 除了扩展 D 并回显构造函数之外什么也不做。为什么 StringMapDC 视为不同的,因为它只是它所排除的某些内容的子类?

编辑:
好的,重新设计了这个示例,使其更接近我实际所做的事情。我测试了它,它确实产生了错误。我在这里所做的是使用泛型类型来确保 clone() 为继承树中实现它的任何人返回正确的类。然后在子类中,我使用 B> 来确保 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>

  }
}

I'm working on a project that has an extensive tree of generic inheritance and dependencies. Go to edit to see better example. The basics look something like this:

class A {
  ...
}

class B {
  ...
}

class C extends B {
  ...
}

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

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

So now I'm going to write a class that contains a specific StringMap type.

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

So far this all works fine. D<C> is actually a very long name and the specific combination is going to show up very frequently in other parts of the code, so I decided to a class for the specific combination so it will be clearer and have a shorter name.

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 gives the error of

Bound mismatch: The type DC is not a valid substitute for the bounded parameter <T extends A> of the type StringMap<T>

So the question is, why does this not just work? DC does nothing but extend D<C> and echo the constructors. Why does StringMap see DC as different when it is just a child class of something it excepts?

EDIT:
OK, reworked the example to be closer to what I'm actually doing. I tested it and it does produce the error. What I'm doing here is using the generic type to ensure that clone() returns the correct class for whoever implements it down the inheritance tree. Then in subclasses, I'm using B<T extends B<T>> to ensure that subclasses of B are passing in a subclass of B as the generic type 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>

  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

初与友歌 2024-10-20 05:27:27

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

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!!!
    }
}

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

You must be doing wrong something else as the following works fine:

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!!!
    }
}

Try to post such a class reproducing your error.

紙鸢 2024-10-20 05:27:27

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

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

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

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

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

这有点麻烦...

As mentioned, your code is OK, although if i can guess, you meant to write the following line, which will indeed cause an error:

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

The reason is the same as that which causes the following to be a problem:

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

The generic type parameter given to a class when defining an identifier's type, i.e. in the lvalue, cannot be instantiated, i.e. in the rvalue, by a type whose parameter inherits the parameter given in the lvalue. If the parameters are different, the types are not considered compatible, even though intuitively they should have been (if generics were implemented in the language a little differently).

It's a bit of a gotcha...

韬韬不绝 2024-10-20 05:27:27

我不太确定为什么要这样做以及要使用 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());

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

我希望这有帮助!

I'm not really sure why you want to do this and what you want to use the StringMap for exactly, but changing the StringMap definition to this will allow what you've done to compile:

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

Which means that the type T must be an Undoable of any type as long as that type is a contravariant of T (indeed T itself). So now you can do this:

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

Having said that, this is just a theoretical exercise - i would strongly recommend you avoid using such complex inheritance hierarchies, but its difficult to suggest an alternative without the full use case.

I hope that helps!

假装爱人 2024-10-20 05:27:27

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

D 之所以有效,是因为 D 与扩展中提到的同一个类。很安全。 D 指的是它本身。 D 扩展 A,字符串>。用它制作一个 StringMap 很好,因为 D 实现了 Undoable>因为 D 扩展了 A,String>,而 A 又扩展了 Undoable>。另一方面,DC 也必须实现 Undoable,这是不可能的,因为它只扩展了 D;一个解决方案是它还可以实现 Undoable,其中需要 DC 方法的新定义才能起作用。这是您遇到的真正问题。我希望这能解决您的问题。

我的老问题:

在类D中,T扩展B,但随后D扩展A>。

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

Hmmm. I hope this isn't ancient old, but I'm solving a problem I also had. I noticed that in D, D must extend B or C must extend D due to a loop-around in A., enough to make me put in a bunch of effort for no one to notice. The problem is in the StringMap class, which strictly wants its own input to extend a generic class whose generic must be its input.

D works because D is the same class mentioned within the extension. It's safe. D refers to itself. D extends A, String>. Making a StringMap with it is good because D implements Undoable> because D extends A, String>, which extends Undoable>. DC, on the other hand must also implement Undoable, which impossible due to it only extending D; a solution could be for it to also implement Undoable where a new definition of methods with DC is needed to work. This is the real problem you are encountering. I hope this solves your problem.

My old problem:

In class D, T extends B, but then D extends A>.

However, instead of returning the expected A or A>, it extends A, String>.
However, D doesn't extend B. Therefore, both A, String> and A. Since inheritance from two of the same interface with different generic enclosed classes is not implemented in Java, T must extend D. However, C does not extend D, which is the problem you are encountering which is a problem you might need to fix in the future.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文