13

同様の機能をエラーなしで実現するにはどうすればよいですか?

class A<K> {
   void f(K x) {}
}

void foo(A<? extends X> a, X x) {
    a.f(x); // AN error: The method f(capture#1-of ? extends X) in the 
            // type A<capture#1-of ? extends X> is not applicable for the 
            // arguments (X)
}

'a' は A<"non-X"> のインスタンスになる可能性があるため、その 'f' は X のインスタンスをパラメーターとして受け入れてはならないため、これが発生することはわかっていますが、パラメーターを強制的に同じタイプ?

より多くのコードは次のとおりです。

テストクラス:

class Test {
   <T> void foo(A<T> a, T x) {
   a.f(x); // now it works!
 }
}

いくつかのクラスで:

Container<X> container;
public void test() {
    X x = new X();
    new Test().foo(container.get(), x);
}

コンテナ クラスは次のとおりです。

public class Container<K> {
    A<? extends K> get() {
    return new A<K>();
    }
}
4

2 に答える 2

18

次のようにして、パラメータを強制的に同じ型にすることができます。

// the first class, A<K>:
class A<K> {
  void f(K x) {}
}

// the second class, defining the method with generic type parameters
class Test {
  <T> void foo(A<T> a, T x) {
    a.f(x); // now it works!
  }
}

// a third class, that uses the above two:
class Main {
  public static void main(final String... args) {
    final Test test = new Test();
    final A<String> a = new A<>();
    test.foo(a, "bar");
  }
}

これが行うことは次のとおりです。メソッドfooはジェネリック型パラメーターを定義し、それを使用して、クラスの型パラメーターが の型、 の 2 番目のパラメーターと一致する必要がTあることを強制します。KAxfoo

、または with<T>など、必要に応じて、問題に適しているかどうかに制限を課すこともできます。ジョニが質問のコメントで尋ねたように、実際には型パラメーターではなく型である場合、これが必要になります。<T extends Bar> void foo(A<T> a, T x) {...}superX<T extends X> void foo(...)


さらにコードを表示すると、問題が明らかになります。

.get()コンテナのメソッドは のインスタンスを返しますA<? extends K>。したがって、取得元のインスタンスの型パラメーターは.get()完全には指定されていません。通常、このような未指定の型を返すのはあまり良い設計ではありません。このような API を改善する方法を示す、Effective Java および Java の多くの API と機能の作成者である Joshua Bloch によるビデオ プレゼンテーションについては、http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu を確認してください。 be&t=22m . 正確に 25'36" で、Joshua Bloch は「戻り値で [ワイルドカード型] を使用しようとしないでください」と述べており、後で説明しています。基本的に、それらを使用しても柔軟性は得られず、 APIのユーザーがそれに対処するのは非常に困難です(あなたはそれを行うことの効果を感じただけです...)。

修正するには、 の署名を に変更してみてください.get()A<K> get()コンテナ クラスは次のようになります。

public class Container<K> {
  A<K> get() {
    return new A<K>();
  }
}

get()がのインスタンスを返すことはわかっているのでA<K>、古い署名を使用する理由はありません。単に知っている情報を失うだけです!

それでも問題が解決しない場合は、問題が別の場所にある可能性があり、さらに多くのコードを表示する必要があります... または、さらに良いことに、他の質問をしてください! :)

于 2013-06-30T12:40:11.233 に答える
6

PECS ルールを念頭に置いて、 X の使用方法を考えると、上限ではなく下限として指定する必要があります。

void foo(A<? super X> a, X x)

この方法では、コンパイラ エラーは発生せず、最も一般的な署名を適用できます。

于 2013-06-30T12:45:54.100 に答える