【问题标题】:How to use Java generics to avoid overwriting inherited methods (template-like behaviour)?如何使用 Java 泛型来避免覆盖继承的方法(类似模板的行为)?
【发布时间】:2013-01-04 11:13:22
【问题描述】:

我想用 Java 制作一个包含节点的图表。图类将被不同的人和不同的算法使用,因此我们将需要针对每种情况使用不同的节点类,比如DefaultNodeSpecialNode extends DefaultNode

现在我希望DefaultNode 包含节点需要工作的所有常规内容,例如直接邻居列表。所以我在DefaultNode中实现了这个列表:

List<DefaultNode> neighbours = new ArrayList<DefaultNode>();

我现在的问题是,我显然也需要 SpecialNode 类中的这个列表,但它应该包含并返回 SpecialNodes。当然,我可以覆盖从DefaultNode 继承的每个类中的列表和addNeighbour() 以及getNeighbours() 方法,但这似乎是多余的,而不是OOP 的工作方式。我认为这将是使用模板的完美案例(如在 C++ 中),但 afaik 在 Java 中没有这样的构造,只剩下泛型。

目前我想出的解决方案如下:

interface INode {}

class DefaultNode<T extends INode> implements INode {

    List<T> neighbours;

    List<T> getNeighbours(){}

    void addNeighbour(T node){}

}

这里,&lt;T extends INode&gt; 括号描述了这个节点的可能邻居。所以对于SpecialNode,我会这样做:

class SpecialNode extends DefaultNode<SpecialNode> {}

现在,虽然这似乎按预期工作,但感觉有点奇怪......我很惊讶我找不到更简单的解决方案,因为这种情况似乎比较普遍。你会如何解决这个问题?我错过了更好/更简单的方法吗?或者上述是一种可行的方法?

【问题讨论】:

  • 如果getNeighborsDefaultNode中,接口中有哪些方法?即,如果你有一个 INode 但不知道它到底是什么类型,你能用它做什么?
  • 你说得对,界面在这里没有多大意义,因为邻居列表和 add/get-methods 不能在那里。虽然它可能包含一般描述节点的其他方法。

标签: java templates generics inheritance


【解决方案1】:

你的方法没有错。事实上,一些标准的接口,比如Comparable就是这样定义的:

public class Fruit implements Comparable<Fruit> {
             ^^^^^                       ^^^^^

【讨论】:

  • 哦,我应该亲眼看到的..!谢谢!所以上面的方法没有错......但是如果有更简单的方法我仍然很感兴趣......因为它看起来很简单:'List neighbours;'或类似的东西......
  • @AlexK: List&lt;this.getClass()&gt; 因为类型擦除而无法工作。
【解决方案2】:

如果你想强制一个节点的邻居是同一类型,你可以使用:

class DefaultNode<T extends DefaultNode<T>> implements INode

虽然我会将接口设为通用接口(并称之为 Node 而不是 INode)。

【讨论】:

  • 但这似乎使得无法实例化 DefaultNode:DefaultNode&lt;DefaultNode&gt; node = new DefaultNode&lt;DefaultNode&gt;(); 无法编译。它确实强制将 SpecialNode 与 SpecialNodes 一起使用,因此可能值得在继承序列中引入一个额外的抽象类..
  • 这是将泛型放在接口上的另一个原因:)。
  • 是的。虽然这意味着我必须创建一个新列表并在每个子类中实现方法,这是我想首先避免的 :) 但我想这是挑剔的,我对抽象类解决方案很满意!
  • 这并不强制邻居是同一类型。考虑class A extends DefaultNode&lt;A&gt;class B extends DefaultNode&lt;A&gt;
  • 那么它与我最初对DefaultNode 的定义有何不同?我能找到的唯一区别是尝试执行 DefaultNode&lt;DefaultNode&gt; node = new DefaultNode&lt;&gt;() 时的编译错误
猜你喜欢
  • 1970-01-01
  • 2011-07-17
  • 2013-03-19
  • 1970-01-01
  • 1970-01-01
  • 2016-01-24
  • 1970-01-01
  • 2020-04-09
  • 2018-01-25
相关资源
最近更新 更多