【问题标题】:How can I make an interface instance method accept arguments of the same class only, really?我怎样才能让接口实例方法只接受同一个类的参数,真的吗?
【发布时间】:2013-08-31 23:02:47
【问题描述】:

SO discussion 提出以下成语:

public interface IComparable<T extends IComparable<T>> {
    int compare(T t);
}

然后允许:

public class Foo implements IComparable<Foo> {
    public int compare(Foo foo) {
        return 0;
    }
}

但是,这个习语不仅仅允许上面的,因为下面的代码也可以编译:

class A implements IComparable<A> {
    public int compare(A a) {return 0;}
}

public class Foo implements IComparable<A> {

    public int compare(A a) {
        return 0;
    }
}

因此(除非我误解了什么)原始成语与远没有那么戏剧性的成语相比并没有真正购买更多东西:

public interface IComparesWith<T> {
    int compare(T t);
}

public class A implements IComparesWith<A> {
    public int compare(A a) {...}
}

那么,有没有一种方法可以真正声明一个接口,使得任何声明实现它的类都有一个方法来与它自己的类的对象进行比较,而没有任何上述漏洞?

我显然无法将以上内容作为评论发布,因此我创建了一个新帖子。

【问题讨论】:

标签: java generics interface


【解决方案1】:

不,这种限制对于所写的泛型是不可能的。您的评估对我来说似乎是正确的。

【讨论】:

    【解决方案2】:

    你是对的:这个习语确实阻止将类与不同的类进行比较。它所做的只是确保比较对象也实现相同的接口。如果要求只比较相同的类型,则可以由实现类强制执行。

    你所说的“漏洞”就是我所说的“故意做你不想做的事情”。

    Foo 对象可以与 A 对象进行比较 IF 需要这样的行为。

    这是一个功能,而不是漏洞。

    如果您希望 Foo 与其他 Foos 具有可比性,则应定义 Foo 以实现 IComparable&lt;Foo&gt;

    如果您希望 FooA 具有可比性,那么您不应该定义Foo 来实现IComaparable&lt;A&gt;。除非他们故意尝试编写损坏的代码,否则为什么会有人这样做?

    @caskey 已经提供了您问题的实际答案:

    不,你不能在 Java 中使用接口做你想做的事。[你必须用类来做]。

    你错过了一件事:

    因此(除非我误解了什么)原始成语与远没有那么戏剧性的成语相比并没有真正购买更多东西:

    public interface IComparable&lt;T&gt;

    原始成语确实给你买了东西。它强制比较对象必须实现IComparable。不太引人注目的示例将允许您不受限制地将实现类与任何对象进行比较。所以...编译器将允许您指定Long、或InputStream、或LinkedHashSet&lt;Byte[]&gt;,或任何东西作为类型参数。

    当你这样看时,很容易看出为什么这个成语如此普遍。

    【讨论】:

      【解决方案3】:

      因此(除非我误解了什么)原来的成语 与远没有那么戏剧性的东西相比,并没有真正买更多的东西:

      它确实买了一些东西,但它和你想的不一样。当有人这样写时,99.9% 的情况下,这并不是他们想要购买的东西。

      那么,有没有办法真正声明一个接口,这样无论 类声明实现它有一个方法来与对象进行比较 自己的类,没有上面那个漏洞?

      没有。因为它在类型安全方面没有用处。 public class Foo implements IComparable&lt;A&gt; 没有任何问题——它是完全类型安全。如果有人想制作一个Foo 可以在某种程度上安全地与A 进行比较,那就太好了。我同意 jahroy'a 的回答——这不是“漏洞”;这是一个功能。为什么让它更通用,只要它是安全的?它不会妨碍你正在做的任何事情。如果你想让你的所有课程都与自己进行比较,那也很好。一切都很好,只要它是类型安全的。

      你应该关心类型和它实现IComparable的类型参数的关系的唯一地方是你使用它的地方,因为那个地方可能合法地需要这样一种关系。所以在那个地方(由可比较类型参数化的泛型类或泛型方法),我们可以很容易地绑定表示可比较类型的类型变量,如下所示:T extends IComparable&lt;? super T&gt;,允许我们保证 T 可以比较自己。

      【讨论】:

      • Comparable 的语义规定如果class A implements Comparable&lt;B&gt;,B 必须是A。如果a1 可以与b 进行比较,a2 可以与b 进行比较,@987654332 @ 必须能够与 a2 进行比较,因此 A 必须是 Comparable&lt;A&gt;。为什么不放松 Comparable 的语义呢?因为我们希望它具有 Comparable 的使用站点可以依赖的某些属性。一个类型需要足够通用来描述一组对象;它还需要足够具体以仅描述这些对象。
      • Comparable 是一种高级类型,用来描述其他可以与自己进行比较的类型。 Java 类型系统不足以描述这一点,因此我们需要求助于语言外的措施,如 javadoc 或命名约定。其他语言,例如Haskell 可以很好地描述它。
      • “Comparable 的语义规定,如果类 A 实现 Comparable,则 B 必须是 A。”不,它没有。
      【解决方案4】:

      不要使用泛型:

      public interface Foo {
          public void doSomething(Foo foo);
      }
      

      【讨论】:

      • 如果您不介意实现类现在可以与任何其他实现类进行比较,则此方法有效。
      • @ChrisHayes “可比”如何相关?标题没有提及可比性,这个答案也没有提及。我已经按照说明回答了这个问题。
      • 我们读的是同一个问题吗?整个问题以“IComparable”为例。然而,实际的界面是无关紧要的。提问者想要一种方法来强制 MyInterface 的实现始终由类 T 实现,即不能将任何其他类放在那里。你的回答没有做到这一点。
      • 如你所说,IComoarable 只是一个例子(即无关紧要)。我的观点是:“不要使用泛型”。我相信这就是问题所在...... OP 在不应该使用泛型的时候使用了泛型。我不明白为什么这会变成这样的圣战:/
      • 只有当你改变问题时,这才是答案。正确的答案是 OP 想要的行为是不可能通过接口实现的;您不能将类型泛型限制为指定泛型值的类的类型。上面的 jahroy 解决了这是否甚至是可取的问题,但这个答案并未涵盖它的可能性或可​​取性。
      【解决方案5】:

      确实如此。我主张我们使用This 作为此类类型参数的常规名称

      public interface IComparesWith<This> 
      {
          int compare(This t);
      }
      

      我之前的回答:Convenient way to write generic interface that points out to its implementor

      【讨论】:

      • 请注意,这只是一个约定(我以前从未听说过),而不是编程语言功能。 This 与普通的T 具有完全相同的功能。
      • 它也避免了使用单个大写字母来表示泛型参数的约定。远离(非常)常见关键字的单个大写字母很可能会导致混淆。
      • 使用This 作为类型参数没有任何意义,并且违反了公认的命名约定而引入了混淆。 -1
      • 约定是人们遵循的。我希望这永远不会成为惯例(幸运的是它不会,因为它没用)。
      • @zhong:这不是解决方法。解决方法是实现相同目标的另一种方法。这并没有实现目标;对于如何实现接口没有编译时间限制,甚至没有任何关于实现接口的类应该如何使用它的指导。更好的方法是创建一个 Javadoc,告诉实现者该做什么。
      猜你喜欢
      • 2015-03-21
      • 1970-01-01
      • 2017-06-20
      • 1970-01-01
      • 2012-07-03
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多