【问题标题】:complementary generic classes互补的泛型类
【发布时间】:2017-04-15 12:45:08
【问题描述】:

我有两个抽象类: 容器、节点

一种Container总会包含同一种Node,一种Node只会属于其对应的Container: NodeTypeA 存储在 ContainerTypeA 中,并且没有其他 Node 子类存储在其中。 NodeTypeB 存储在 ContainerTypeB 中,没有其他 Node 子类存储在其中。从 Node 到它的 Container 的反向引用也应该知道 Container 的类型,所以关系是双向的。

我在 Java 中实现这个时遇到问题。

我是这样做的:

Container<C extends Container<C,N>, N extends Node<C,N>>
Node<C extends Container<C,N>, N extends Node<C,N>>

但是,当我在 Container 中定义以下字段时,出现错误:

private List<N> nodes;

错误消息说我应该用 Node 替换 N。这对我来说似乎是多余的。为什么会发生这种情况,我怎样才能让程序理解这一点

N

应该等于

Node<C,N>

测试用例:

https://ideone.com/wam0gi

这样做的目的:

有许多不同种类的节点以及它们可以交互的许多不同种类的方式。但是,它们有一些共同的主题。 Container 和 Node 应该是抽象类,我可以在其中定义方法和抽象方法来定义这些常见的主题。 ContainerA 和 NodeA 将一起定义一种特定的交互方法。我为此使用泛型,因为如果我的 IDE 足够聪明,可以知道 ContainerA 中的任何节点始终是 NodeA,并且 NodeA 的所有者始终是 ContainerA,那么我可以避免一些不必要的类型转换.

(注:此题类似但不等于Complementary generic types

【问题讨论】:

  • 确切的错误信息是什么?您能否包含一个导致此错误的最小但完整的类?
  • 这里看起来不错:ideone.com/m1Qi2n。请构造一个minimal test-case
  • 最小测试用例:ideone.com/wam0gi
  • 关键字“abstract”应在关键字“class”之前。
  • 嗯。我匆匆写下。奇怪的是网站的编译器没有首先抱怨这个,而只是抱怨泛型。

标签: java generics generic-programming


【解决方案1】:

除了几个微不足道的错误(abstract 应该在 java 中的 class 之前,在第 16 行的 Node 的构造函数中错误的类型变量 L,尝试在第 18 行访问私有字段),你的语义问题在第 18 行。this 的类型是 Node&lt;C,N&gt;,而不是 N

实现目标的一种方法是向Node 添加一个抽象方法,该方法返回N,所有子类将通过返回this 来实现它。

abstract protected N me();

然后,一旦你为Container 添加了一个合适的setter,你将把第18行改为

owner.add( me() );

【讨论】:

    【解决方案2】:

    我怎样才能让程序理解这一点 N 应该等于 Node&lt;C,N&gt;

    他们不相等。 N 扩展 Node&lt;C, N&gt;

    private List<N> nodes;
    

    表示Node&lt;C, N&gt; 的某个子类的列表。

    您将很难添加到这样的列表中。

    考虑

    List<N> nodes = ...;
    
    Node<C, N> node = new Node<>(...);
    nodes.add(node);  // ERROR because node might not be the right subclass
    

    List<Node<C, N>> nodes = ...;
    
    Node<C, N> node = new Node<>(...);
    nodes.add(node);  // OK.
    

    List<N> nodes = ...;
    N node = new Node<C, N>(...);   // ERROR.  Not all Node<C, N> are N
    // N is a sub-type not a super-type of Node<C, N>
    nodes.add(node);
    

    如果Node 是最终的,你说它不是,“””

    有许多不同种类的节点

    """,那你就可以了

    N node = (N) new Node<C, N>(..);  // Unchecked conversion
    

    但是这种类型擦除规则的弯曲是不必要的,即使它在您的程序上下文中是安全的。

    【讨论】:

      猜你喜欢
      • 2013-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      • 2010-11-15
      • 2023-02-10
      相关资源
      最近更新 更多