使用方法参数超类的接口实现

发布于 2024-09-27 17:24:22 字数 1094 浏览 4 评论 0原文

作为主题中一般问题的一个实际示例,我想在 Set 接口中实现 containsAll 方法,

public boolean containsAll(Iterable<?> c) { /* ... */ }

我认为应该允许这样做,因为 CollectionIterable 意味着这样的 containsAll 将满足接口要求。同样,更一般地说,能够使用参数超类实现接口似乎应该可行。

然而,Eclipse 说没办法(没有直接尝试过 javac)——有人能解释一下原因吗?我确信规范中有一些东西使它成为现在的样子,但我也想了解需求的动机。或者我是否缺少诸如 Iterable 之类的东西,而不是 Collection 的超类?

作为一个附带问题 - 假设我声明了两种方法,在使用 Collection 参数进行调用时,是否始终会首选具有 Iterable 签名的方法?

Eclipse 错误:

如果我删除带有 Collection 签名的方法,只留下 Iterable 一个(参见错误后),我会得到以下信息:

The type BitPowerSet must实现继承的抽象方法 Set.containsAll(Collection)

具体实现是:

@Override public boolean containsAll(Collection<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}
public boolean containsAll(Iterable<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}

As a practical example of the general question in the subject, I'd like to implement the containsAll method in the Set interface with

public boolean containsAll(Iterable<?> c) { /* ... */ }

I figure this should be allowed, since Collection is Iterable meaning such a containsAll would cover the interface requirement. Likewise, more generally being able to implement interfaces with argument superclasses seems like it should work.

However, Eclipse says no way (haven't tried just javac straight-up) - can someone explain the reason for that? I'm sure there's something in the spec which makes it the way it is, but I'd like to understand the motivation for requirement as well. Or am I missing something like Iterable<?> not being a superclass of Collection<?>?

As a side question - given I'm declaring two methods would the method with the Iterable signature always be preferred on calls with a Collection argument?

Eclipse Error:

If I remove the method with the Collection signature, just leaving the Iterable one (see after error), I get the following:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

The exact implementation being:

@Override public boolean containsAll(Collection<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}
public boolean containsAll(Iterable<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}

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

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

发布评论

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

评论(3

2024-10-04 17:24:22

由于您要实现的接口声明了(抽象)方法 containsAll(Collection),因此您必须使用这个确切的签名来实现它。 Java 不允许您实现/重写具有比原始参数类型更广泛的参数类型的方法。这就是为什么当您使用 Collection 签名注释掉您的方法时会出现错误。

您没有显示您声称在未注释掉该方法时遇到的其他错误,但我想它可能必须通过不明确的方法重载来执行某些操作。

Since the interface you are implementing declares the (abstract) method containsAll(Collection<?>), you must implement it with this exact signature. Java does not allow you to implement/override a method with a wider parameter type than the original. This is why you get the error you show when you comment out your method with the Collection signature.

You don't show the other error you claim to get when the method is not commented out, but I guess it might have to do something with ambiguous method overloading.

绝不放开 2024-10-04 17:24:22

我对为什么java有这个限制的猜测是,假设你有:

class A {
    void foo(String s) { ...  }
}

class B extends A {
    // Note generalized type
    @Override void foo(Object s) { ...  }
}

现在,如果你有class C extends B并且它想要覆盖foo,则不清楚它的参数是什么应该采取。

例如,C 首先直接扩展 A,覆盖 void foo(String s),然后将其更改为扩展 B。在这种情况下,C 现有的 foo 覆盖将是变得无效,因为 B 的 foo 应该能够处理所有 Object,而不仅仅是 String

My guess as to why java has this restriction is, say you have:

class A {
    void foo(String s) { ...  }
}

class B extends A {
    // Note generalized type
    @Override void foo(Object s) { ...  }
}

Now if you have class C extends B and it wants to override foo, it's not clear what argument it should take.

Say for example C extended A directly at first, overriding void foo(String s), and then it was changed to extend B. In this case C's existing override of foo would become invalid because B's foo should be able to handle all Objects, not just Strings.

暮光沉寂 2024-10-04 17:24:22

参数类型是方法签名的一部分,因此 jvm 需要一个具有完全相同签名的方法来查找重写。 containsAll(Iterable) 将具有与 containsAll(Collection) 不同的签名。

如果我没记错的话,编译器必须使用一些解决方法来使泛型工作,尽管有这个限制。

对于第二个问题,编译器更喜欢 Collection 参数,因为它是 Iterable 的子类型,这使得 Collection 方法比 Iterable 方法更具体。

The argument types are part of the method signature so the jvm needs a method with exact the same signature to find overrides. A containsAll( Iterable) will have a different signature than containsAll(Collection).

If I remember right the compiler has to use some workarounds to make generics work in spite of this limitation.

To your second question, the compiler would prefer the Collection argument since it is a subtype of Iterable, this makes the Collection method more specific than the Iterable one.

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