2011-11-18 12 views
12

java.lang.ClassのgetInterfaces()メソッドが、クラス []ではなく、クラス<?> []を返すのはなぜですか?

は一例として、次のアプリケーションを確認してください(質問をクリアするには、「T」のクラスで宣言された型パラメータを参照):

public class TestClass { 

    interface InterfaceA{} 

    interface InterfaceB{} 

    interface InterfaceC{} 

    class ClassA implements InterfaceA, InterfaceB, InterfaceC{} 


    public static void main(String[] args){  

     Class<? super ClassA> superClass1 = ClassA.class; 
     Class<? super ClassA> superclass2 = InterfaceA.class; 
     Class<? super ClassA> superclass3 = InterfaceB.class; 
     Class<? super ClassA> superclass4 = InterfaceC.class; 

     for(Class<?> clazz : ClassA.class.getInterfaces()){ 
      System.out.println(clazz.getName()); 
     } 
    } 
} 

出力は1つが期待するものです:

TestClass$InterfaceA 
TestClass$InterfaceB 
TestClass$InterfaceC 

ので、上記の例に基づいて、我々は、コンパイラがInterfaceA 会う目をしていることを認識していることがわかります他のすべてのインタフェースと同様に、ワイルドカードの境界にも適用されます。

直感的に、私は次のように安全であると期待されるが、そうではありません。

Class<? super ClassA>[] interfaces = ClassA.class.getInterfaces(); 

署名は、それがクラスを返すことを言うので、コンパイラは、警告を与えます。しかし、クラスのJavadocは次のように述べている:

このオブジェクトがクラスを表す場合、戻り値は クラスによって実装されるすべてのインタフェースを表すオブジェクトを含む配列 あります。

「このオブジェクト」は、ここではClassAです。我々は呼んでいる場合は、この声明に基づき、:

ClassA.class.getInterfaces() 

その後、我々は返される配列内のすべてのClass<?>ClassAのスーパー型への参照が含まれていることを、論理的に、知っています。参照の追加点として

Java言語リファレンス第3版から:

クラスは、必ずしもその直接 スーパークラスと直接的上位が行うすべてのインタフェースを実装しています。この(複数の)インターフェイス の継承により、オブジェクトは実装を共有することなく(複数の)共通の動作をサポートできます。 本明細書の他の部分を読む

、I、クラスTによって実装またはexteneded任意のクラスまたはインタフェースが境界<? super T>に落ちるだろうと思うだろう。

EDITEDは:

私の質問のための具体的な理由が存在しないことが示唆されています。私は例を提供します:

1 import java.util.Map; 
2 import java.util.HashMap; 
3  
4 public class MapWrapper<T> { 
5  private final Map<Class<?>, OtherClass<T,?>> map = new HashMap <Class<?>, OtherClass<T,?>>(); 
6  
7  public <W> void addToMap(Class<W> type, OtherClass<T,? super W> otherClass){ 
8   map.put(type, otherClass); 
9  } 
10  
11  public <W> OtherClass<T,? super W> getOtherClassForAnyInterface(Class<W> type){ 
12   if(type.getInterfaces()!=null){ 
13    for(Class<?> interfaceType : type.getInterfaces()){ 
14     // Here, a cast is necessary. It throws a compiler warning for unchecked operations (rightfully so) 
15     OtherClass<T,? super W> otherClass = (OtherClass<T,? super W>)getOtherClassForInterface(interfaceType); 
16     if(null!=otherClass){ 
17      return otherClass; 
18     } 
19    } 
20   } 
21   return null; 
22  } 
23  
24   
25  public class OtherClass<T,V> {} 
26  
27 } 

は、問題はあなたが正しい型を得るために<? super W>にキャストする必要が線15です。コンパイラの警告を抑制することはできますが、それは正当化されますか?このキャストが真実でないシナリオがありますか?

答えて

5

あなたが正しいです、返品の種類はより具体的かもしれません。

しかし、Class<? super X>はそれほど有用ではありません。ほとんどの用途にはClass<?>で十分です。

G<? super X>は通常GTを受け入れる方法を持っている必要があり、有用であるため、我々は、宣言G<T>を持っている場合。たとえば、List<T>add(T)です。だから、List<? super X>が有用である、我々は

Classは、このような方法を持っていないことに(タイプXxビーイング)をadd(x)を呼び出すことができます。

本当に必要な説得力のあるユースケースがありますかClass<? super ClassA>

非配列の例

<T super Integer> void add(T number) // hypothetical! currently illegal in Java

そして、あなたはこれらの変数の宣言があります:

Integer anInteger Number aNumber Object anObject String aString

+2

クラスは、実際にはTのスーパークラスを使用するメソッドを持たないかもしれませんが、型自体を表すので、スーパータイプに関する情報を提供すると主張します。 ClassのgetSuperclass()メソッドを見ると、戻り値の型は 'Class 'です。この場合、getInterfaces()が私のように戻ってくるのがさらに適切です。彼らが考えているように、あなたが示唆しているように、そのクラスは決してワイルドカードを使用してアクセス可能なこれらのメソッドを使用しないでしょうから、クラスは ''と指定されたスーパークラスを提供します。 – sager

+0

APIデザイナーの間違いでしょう。とにかくそれは問題ではないと私は主張している。 – irreputable

+0

このようにClassを使用する具体的なケースを追加しました。それは現在、探求自体にあります。 – sager

0

ここでも、あなたがこのジェネリックメソッド宣言を持っているとしましょう<T super Integer>とあなたの意図(それが合法であるならば) w add(anInteger)およびadd(aNumber)、もちろんadd(anObject)であるが、add(aString)ではない。文字列はオブジェクトなので、add(aString)はまだとにかくコンパイルされます。それは私を助けたStack Overflow - Bounding generics with 'super' keyword

:から

コピー。あなたも助けてくれるかもしれません:)

関連する問題