13

(質問を明確にするために、「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());
        }   
    }
}

出力は期待されるものです:

TestClass$InterfaceA
TestClass$InterfaceB
TestClass$InterfaceC

したがって、上記の例に基づいて、他のすべてのインターフェースと同様に、InterfaceAワイルドカードの境界を満たしていることをコンパイラが認識していることがわかります。

直感的には、次のことは安全だと思いますが、そうではありません。

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

署名がクラスを返すと述べているため、コンパイラは警告を出します。ただし、Class の javadoc には次のように記載されています。

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

この場合、「このオブジェクト」は を指しますClassA。このステートメントに基づいて、次のように呼び出します。

ClassA.class.getInterfaces()

Class<?>論理的には、返された配列のすべてに のスーパー タイプへの参照が含まれることがわかりClassAます。

追加の参照ポイントとして:

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

クラスは、直接のスーパークラスと直接のスーパーインターフェースが行うすべてのインターフェースを必然的に実装します。この (複数の) インターフェイス継承により、オブジェクトは実装を共有することなく (複数の) 共通の動作をサポートできます。

これと仕様の他の部分を読むと、クラスによって実装または拡張されたクラスまたはインターフェースはすべてT境界に分類されると思います<? super T>

編集:

私の質問には具体的な理由がないことが示唆されています。例を挙げます:

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 行目です。正しい型を取得するには、にキャストする必要があります。コンパイラの警告は抑制できますが、正当化されますか? このキャストが正しくないシナリオはありますか?

4

2 に答える 2

5

そうです、戻り値の型はより具体的である可能性があります。

ただし、Class<? super X>とにかくあまり役​​に立ちません。Class<?>ほとんどの用途には十分です。

宣言がある場合、 が有用であるG<T>ためには、通常、 を受け入れるメソッドが必要です。たとえば、を持っています。便利なので、それを呼び出すことができます(型である)G<? super X>GTList<T>add(T)List<? super X>add(x)xX

Classにはそのようなメソッドはありません。

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

于 2011-11-18T23:43:11.443 に答える