6

件名の一般的な質問の実用的な例として、インターフェイスにcontainsAllメソッドを実装したいと思いますSet

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

これは、インターフェース要件をカバーすることをCollection意味Iterableするため、許可する必要があると思います。containsAll同様に、より一般的には、引数のスーパークラスを使用してインターフェイスを実装できるようにすることも機能するはずです。

しかし、Eclipseはそうは言いません(javacをまっすぐに試したことはありません)-誰かがその理由を説明できますか? 仕様にはそれをそのままにしている何かがあると確信していますが、要件の動機も理解したいと思います。Iterable<?>または、のスーパークラスではないなどの何かが欠けていCollection<?>ますか?

副次的な質問として、2 つのメソッドを宣言しているとすれば、引数Iterableを使用した呼び出しでは常に署名付きのメソッドが優先されますか?Collection

日食エラー:

Collection署名付きのメソッドを削除して、 Iterable1 つだけ残すと (エラーの後に参照)、次のようになります。

The type BitPowerSet must implement the inherited abstract method Set<Long>.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;
}
4

3 に答える 3

5

実装しているインターフェイスは (抽象) メソッドcontainsAll(Collection<?>)を宣言しているため、この正確なシグネチャで実装する必要があります。Java では、元のパラメーター タイプよりも広いパラメーター タイプのメソッドを実装/オーバーライドすることはできません。Collectionこれが、署名でメソッドをコメントアウトすると表示されるエラーが発生する理由です。

メソッドがコメントアウトされていない場合に発生すると主張する他のエラーは表示されませんが、あいまいなメソッドのオーバーロードで何かを行う必要があると思います。

于 2010-10-16T16:21:16.537 に答える
2

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を拡張するように変更されたとします。この場合、Bはsだけでなくすべてのsを処理できるはずfooなので、Cの既存のオーバーライドは無効になります。 fooObjectString

于 2010-10-16T16:34:44.820 に答える
0

引数タイプはメソッドシグネチャの一部であるため、jvmは、オーバーライドを見つけるためにまったく同じシグネチャを持つメソッドを必要とします。containsAll(Iterable)は、containsAll(Collection)とは異なるシグネチャを持ちます。

私の記憶が正しければ、この制限にもかかわらず、コンパイラーはジェネリックスを機能させるためにいくつかの回避策を使用する必要があります。

2番目の質問に対して、コンパイラーはCollection引数を優先します。これはIterableのサブタイプであるため、これにより、CollectionメソッドがIterableメソッドよりも具体的になります。

于 2010-10-16T16:55:30.507 に答える