2011-11-18 12 views
12

(para aclarar la cuestión, 'T' se refiere a un parámetro de tipo declarado en la clase)¿Por qué el método getInterfaces() de java.lang.Class devuelve Class <?> [] y no Class <? super T> []?

A modo de ejemplo, revise la siguiente aplicación:

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

La salida es lo que uno esperaría :

TestClass$InterfaceA 
TestClass$InterfaceB 
TestClass$InterfaceC 

por lo tanto, en base a este ejemplo anterior, podemos ver que el compilador reconoce que InterfaceA hace reúnen º e los límites del comodín, como lo hacen todas las otras interfaces.

Intuitivamente, yo esperaría que los siguientes son seguros, pero no lo es:

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

El compilador da una advertencia, porque la firma dice que vuelva Clase; sin embargo, el javadoc para la clase afirma lo siguiente:

Si este objeto representa una clase, el valor de retorno es una matriz objetos que contienen representan a todas las interfaces implementadas por la clase .

'Este objeto' se refiere en nuestro caso a ClassA. Sobre la base de esta declaración, si llamamos:

ClassA.class.getInterfaces() 

entonces sabemos que, lógicamente, que cada Class<?> en la matriz devuelta contendrá una referencia a un tipo de súper ClassA.

Como un punto adicional de referencia:

Desde el lenguaje Java de referencia, tercera edición:

Una clase implementa necesariamente todas las interfaces que sus directos superclases y superinterfaces directas hacen. Esta herencia (múltiple) de interfaz permite a los objetos soportar (múltiples) comportamientos comunes sin compartir ninguna implementación.

La lectura de este y otras partes de la especificación, yo creo que cualquier clase o interfaz implementada o exteneded por una clase T caerían en los límites <? super T>.

Editado:

Se ha sugerido que no hay ninguna razón concreta para mi pregunta. Voy a dar un ejemplo:

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 } 

El problema está en la línea 15. Hay que echar a <? super W> para obtener el tipo correcto. La advertencia del compilador puede ser suprimida, pero ¿está justificada? ¿Hay algún escenario donde este lanzamiento no sea cierto?

Respuesta

5

Tiene razón, el tipo de devolución podría ser más específico.

Sin embargo, Class<? super X> no es muy útil de todos modos. Class<?> es suficiente para la mayoría de los usos.

Si tenemos una declaración G<T>, por G<? super X> para ser útil, por lo general G debería tener métodos que aceptan T. Por ejemplo, List<T> tiene add(T). Así List<? super X> es útil, podemos llamar add(x) en él (x ser de tipo X)

Class no tiene tales métodos.

¿Tiene un caso de uso convincente que realmente necesita Class<? super ClassA>?

+2

La clase puede no tener tales métodos que usen realmente cualquier superclase de T, pero, al representar un tipo en sí mismo, pretende proporcionar información sobre los súper tipos. Si observa el método getSuperclass() de Class, su tipo de devolución es 'Clase '. Siendo este el caso, parece incluso más apropiado que getInterfaces() regrese de manera similar a mí. Si estuvieran pensando, como sugiere, que la Clase nunca usaría ninguno de esos métodos accesibles al permitir el comodín delimitado, ¿por qué Class proporcionaría una superclase que se especifica como ''? – sager

+0

Probablemente es un error del diseñador de API. Estoy argumentando que no importa de todos modos. – irreputable

+0

He agregado un caso concreto de uso de clase de esta manera. Está en la búsqueda en sí ahora. – sager

0

Una vez más, vamos a decir que usted tiene esta genérica declaración de método:

Un no-array ejemplo

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

Y tienes estas declaraciones de variables:

Integer anInteger Number aNumber Object anObject String aString

Su intención con <T super Integer> (si es legal) es que debe w add(anInteger), y add(aNumber), y por supuesto add(anObject), pero NO add(aString). Bueno, String es un Objeto, por lo que add(aString) seguiría compilando de todos modos.

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

Me ayudó. Puede ayudarlo también :)

Cuestiones relacionadas