【问题标题】:How can I make an interface instance method accept arguments of the same class only?如何使接口实例方法仅接受同一类的参数?
【发布时间】:2011-07-06 15:31:36
【问题描述】:

我想使用这样的界面:

public interface ResultItem {
    public int getConfidence();
    public boolean equals(ResultItem item);
    public ResultItem cloneWithConfidence(int newConfidence);
}

我已经通过代表语音识别结果的不同类型的对象来实现它。

我的想法是,我只想比较同类的结果。也就是说,如果我创建一个实现ResultItem 的类IntResult,我希望方法签名变为:

public boolean equals(IntResult item);
public IntResult cloneWithConfidence(int newConfidence);

我觉得我的界面存在设计缺陷,因为现在我对 cloneWithConfidence 和其他返回 ResultItem 的方法的结果使用了非常丑陋的强制转换。

有没有更好的办法?

【问题讨论】:

  • 如果你按照你发帖的方式做会发生什么?
  • 你最好继续哭。您需要为 equals 覆盖 Object.equals(Object other) 以用于集合等。忘记您的专用版本,它可能更好但不会在任何地方使用(除非您明确调用)。 编写专用版本,您可能会忘记编写最重要的版本。
  • 将对象与其他任意类型的对象进行比较并没有什么不妥之处。当被问及是否等于 Odie(一只狗)时,加菲猫(一只猫)不应该尖叫,无论他会感到多么愤慨。他应该简单地回答不,他是不平等的。如果加菲猫能识别出任何与他平等的事物,那么无法识别某些事物并不意味着他不知道自己是否平等。相反,无法识别某事本身就证明他不等于它。

标签: java interface methods


【解决方案1】:

有一个常见的成语如下:

public interface ResultItem<T extends ResultItem<T>> {
    public int getConfidence();
    public boolean equals(T item);
    public T cloneWithConfidence(int newConfidence);
}

public class IntResult implements ResultItem<IntResult> {
  //...
}

【讨论】:

  • 当我们这样做时仍然没有语法糖增益(编译器错误)ResultItem item = new IntResultItem(); IntResultItem iResultItem = item.cloneWithConfidence(100);
  • 我非常接近 :) 我几乎做到了这一点,只是我认为我会通过递归使编译器崩溃。
  • @aix 这个解决方案实际上给我带来了很多麻烦。在部分代码中使用 ResultItem 时,我现在一直收到警告。另外,我声明了一个列表List&lt;IntResult&gt;,我不能将它作为List&lt;ResultItem&gt; 类型的参数传递。编译器不接受它。知道为什么吗?
  • @Dunaril 1. 关于警告,您必须酌情使用ResultItem&lt;IntResult&gt;ResultItem&lt;?&gt;。 2. 第二个问题并非针对此解决方案:尝试在预期为 List&lt;Object&gt; 的地方传递 List&lt;Integer&gt;,您将看到相同的行为。
  • @aix 谢谢。那么第二个问题有解决方法吗?
【解决方案2】:

不是你的问题的真正答案,而是一个重要的评论(我认为):

如果您希望您的 equals 方法可用于集合和类似对象中的对象,则需要实现 public boolean equals(Object o),它应该适用于与各种对象的比较(但在大多数情况下返回 false)。您可能还有一个参数类型更窄的方法,并且在实现中委托如下:

public class IntResult {
    public boolean equals(Object o) {
        return o instanceof IntResult &&
             this.equals((IntResult)o);
    }
    public boolean equals(IntResult that) {
        // TODO
    }

}

确保您遵守 equals 合约中的所有条件,即对称性、自反性、传递性和兼容的 hashCode 实现。

【讨论】:

  • 我认为这样的答案提供了额外的价值并且很重要 (+1)
  • 恕我直言,您的“不是真正的答案”比真正的答案更有价值。但是,我强烈建议不要使用参数类型更窄的附加方法。
  • @maaartinus:也许附加的方法应该是私有的并且命名为equals以外的名称,例如equalsImpl等。当您不必检查正确的类型时,通常更容易实现。
【解决方案3】:

好吧,你可以让它通用:

public interface ResultItem<T extends ResultItem<T>> {
    public boolean equals(ResultItem<T> item);
}

那么你需要让IntResult实现ResultItem&lt;IntResult&gt;

当然,这并不能阻止其他班级的行为不端,例如FloatResult 实现了 ResultItem&lt;IntResult&gt;,但当所有类 都表现良好时,它会使各种 API 工作。

【讨论】:

  • 恕我直言,我不明白为什么我们需要这种复杂的表格。见:stackoverflow.com/questions/18553621/…
  • @MarcusJuniusBrutus:您收到的答案基本上是“不,这不可能。”这个答案展示了 的可能性......虽然它无论如何都不完美,但它仍然允许更愉快的 API - 请查看 Enum 以获取此示例。
猜你喜欢
  • 2012-07-03
  • 1970-01-01
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 2016-10-16
  • 2016-01-27
  • 1970-01-01
相关资源
最近更新 更多