2013-06-30 9 views
11

どのようにして同様の機能をエラーなく達成できますか?Java汎用パラメータを同じタイプに強制する

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) 
} 

私は「」<「非X」>のインスタンスになる可能性があるため、それが起こることを知って、その「F」ので、パラメータとしてXのインスタンスを受け入れますが、どのようにすることができてはなりませんパラメータを同じタイプにするように強制しますか?ここで

は、より多くのコードです:

Testクラス:

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

Xはクラスまたは型パラメータですか? – Joni

答えて

17

することができます力:ここ

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

は、コンテナクラスです:いくつかのクラスで

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

パラメタ次の手順を実行して、同じタイプであるとERS:

// 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"); 
    } 
} 

何これが行うことです:ジェネリック型パラメータTを定義し、クラスAKタイプのパラメータが一致しなければならないことを強制するためにそれを使用していますfoo方法xのタイプ、fooの第2パラメータです。

<T>にも制限を課すこともできます。たとえば、<T extends Bar> void foo(A<T> a, T x) {...}、またはsuperなど、問題に適している場合は制限を課すことができます。 として、Xは実際には型のパラメータではなく、<T extends X> void foo(...)を使用します。


コードを表示した後は、問題が解決します。

コンテナのメソッド.get()は、A<? extends K>のインスタンスを返します。したがって、.get()から取得するインスタンスの型パラメータは完全には指定されていません。通常、そのような不特定の型を返すのはあまり良い設計ではありません。このようなAPIを改善する方法を示す、効果的なJavaの著者であるJoshua BlochとJavaの多くのAPIと機能については、http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu.be&t=22mを参照してください。ジョシュア・ブロッホは正確には25'36 "で、"ワイルドカード型を戻り値に使用しないでください "と言い、後で説明します。基本的には、それらを使用することによって柔軟性を失うことはありません。 APIのユーザーがそれに対処するのは辛いです(ちょうどその効果を感じました...)。

修正するには、.get()の署名を変更するだけでコンテナクラス次のようになります。

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

古い署名を使用する理由はありません、get()A<K>のインスタンスを返していることを知っていますので:それは単にあなたが既に知っている情報を失うことになります!

これがまだうまくいかない場合は、問題が他の場所にある可能性があります。さらにコードを表示する必要があります。他の質問もしてください。:)

+0

しかし、どのように使用できますか? タイプA のメソッドfoo(A 、T)は、引数には適用されません(A ?extends X>、X) – Evgeny

+0

あなたはクラス 'Test'を' A'の内部クラスとして定義しているようですが、これは私が上に示したものではありません。 –

+0

これは問題ではないようです:エラーは 'Testの型のメソッドfoo(A 、T)は引数には適用されません(A 、X)' – Evgeny

6

念頭にPECS ruleを維持し、あなたがXを使用している方法を与え、あなたの代わりに上限の下のように指定する必要があります。

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

何のコンパイルエラーが生成されない。この方法で、あなたは適用可能な最も一般的な署名を持っています。

+1

これは正確には言うものではありません:OPは、 'X'を' A a'と 'X x'の両方で*同じ*タイプにする方法を求めています。たぶん彼はあなたが答えたものを望んでいますが、質問はそれから言い換えるべきです。 –

+0

OPは「同様の機能をエラーなく達成するにはどうすればよいですか?マルコの答えはそれだけです。 – meriton

+0

@meriton、確かに。しかし、あまりにもあまりにも漠然としているようだ。 –

関連する問題