2011-11-18 15 views
12

(Per chiarire la questione, 'T' si riferisce a un parametro di tipo dichiarata in classe)Perché il metodo getInterfaces() di java.lang.Class restituisce la Classe <?> [] e non la Classe <? super T> []?

A titolo di esempio, consulta la seguente applicazione:

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

L'uscita è quello che ci si aspetterebbe :

TestClass$InterfaceA 
TestClass$InterfaceB 
TestClass$InterfaceC 

Quindi, sulla base di questo esempio di cui sopra, possiamo vedere che il compilatore riconosce che InterfaceA fa incontrano ° I limiti del carattere jolly, come fanno tutte le altre interfacce.

Intuitivamente, mi aspetto che la segue per essere al sicuro, ma non lo è:

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

Il compilatore dà un avvertimento, perché la firma dice che restituisce classe; tuttavia, il javadoc per Classe membri le seguenti:

Se questo oggetto rappresenta una classe, il valore restituito è un array contenenti oggetti che rappresentano tutte le interfacce implementate dalla classe .

'Questo oggetto' si riferisce nel nostro caso a ClassA. Sulla base di questa affermazione, se chiamiamo:

ClassA.class.getInterfaces() 

allora sappiamo, logicamente, che ogni Class<?> nella matrice restituita conterrà un riferimento a un super tipo di ClassA.

Come un ulteriore punto di riferimento:

Dal Java Language Reference, Third Edition:

Una classe implementa necessariamente tutte le interfacce che i suoi diretti superclassi e superinterfacce dirette fanno. Questa (più) interfaccia ereditaria consente agli oggetti di supportare (più) comportamenti comuni senza condividere alcuna implementazione.

La lettura di questa e di altre parti della specifica, penserei che qualsiasi classe o interfaccia implementata o exteneded da una classe T cadrebbero nella i limiti <? super T>.

Modificato:

È stato suggerito che non v'è alcuna ragione concreta per la mia domanda. Fornirò un esempio:

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 } 

Il problema è alla riga 15. Si deve lanciare per <? super W> per ottenere il tipo corretto. L'avviso del compilatore può essere soppresso, ma è giustificato? C'è qualche scenario in cui questo cast non è vero?

risposta

5

Hai ragione, il tipo di reso potrebbe essere più specifico.

Tuttavia, Class<? super X> non è comunque molto utile. Class<?> è sufficiente per la maggior parte degli utilizzi.

Se abbiamo una dichiarazione G<T>, per G<? super X> di essere utile, di solito G dovrebbe avere metodi che accettano T. Ad esempio, List<T> ha add(T). Così List<? super X> è utile, possiamo chiamare add(x) su di esso (x essendo di tipo X)

Class non hanno tali metodi.

Avete un caso d'uso convincente che avete veramente bisogno di Class<? super ClassA>?

+2

La classe potrebbe non avere tali metodi che effettivamente usano una superclasse di T, ma, rappresentando un tipo stesso, afferma di fornire informazioni sui super-tipi. Se si guarda il metodo getSuperclass() di Class, il suo tipo restituito è 'Classe '. Stando così le cose, sembra ancora più appropriato che getInterfaces() ritorni in modo simile a me. Se pensassero, come lei suggerisce, quella Classe non userebbe mai nessuno di quei metodi accessibili accettando il carattere jolly limitato, perché Class fornirebbe una superclasse che viene specificata come ''? – sager

+0

Probabilmente è un errore del progettista API. Sto sostenendo che non importa comunque. – irreputable

+0

Ho aggiunto un caso concreto di utilizzare Class in questo modo. È nella ricerca stessa ora. – sager

0

Anche in questo caso, diciamo che avete questa dichiarazione metodo generico:

Un non-array esempio

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

E avete queste dichiarazioni di variabili:

Integer anInteger Number aNumber Object anObject String aString

La tua intenzione con <T super Integer> (se è legale) è che dovrebbe w add(anInteger) e add(aNumber) e, naturalmente, add(anObject), ma NON add(aString). Beh, String è un oggetto, quindi add(aString) si compilerebbe comunque.

copia da: Stack Overflow - Bounding generics with 'super' keyword

mi ha aiutato. Può aiutarti anche tu :)

Problemi correlati