2011-08-31 8 views
10

Hoy me encontré con algo interesante. Supongamos la siguiente clase de Java 6:Reemplazando un método que usa borrado de tipo

public class Ereasure { 

    public Object get(Object o) { 
     return null; // dummy 
    } 

    public static class Derived<T> extends Ereasure{ 
     // (1) 
     @Override 
     public Object get(T o) { 
       return super.get(o); 
     } 
     // (2) 
     /* 
     @Override 
     public Object get(Object o) { 
       return super.get(o); 
     }*/ 

    } 
} 

Si intenta compilar el ejemplo anterior, el compilador dice Ereasure.java:9: método no anula ni poner en práctica un método de un supertipo @ Override Si quita la anotación @Override (que no debería ser necesaria), dice Ereasure.java:8: name clash: get (T) en Ereasure.Derived y get (java.lang.Object) en Ereasure tiene la misma eliminación , sin embargo, ninguno reemplaza al otro Esto es un poco contradictorio, ya que T debe entrar en Object y, por lo tanto, anular el método get de las clases padre.

Si deja (1) no anotados y descomenta (2) (1) sobrecargas (2) tampoco funcionaría. salida del compilador:

Ereasure.java:15: get(T) is already defined in Ereasure.Derived 
    public Object get(Object o) { 

Como conclusión, T está siendo ereased al objeto, pero no puede anular el padre método GET.

Mi pregunta es ahora, ¿por qué no compila al menos uno de los ejemplos?

+0

@ toto2 Creo que es cierto, pero también creo que es un caso de esquina aparentemente indocumentado interesante. De acuerdo con las notas del compilador solar en Type Erasure, la definición del método en Derived debe convertir el tipo ilimitado en Obtiene get to public Object get (Objeto o) que, dado que es una subscripción del padre, debe anularse. Creo que tiene razón en que no hay forma de convertir esta cosa en bytecode para resolver la ambigüedad del envío de métodos resultante del tipo ilimitado. – nsfyn55

Respuesta

2

En una simple suposición, el compilador no usa la vista genérica al calcular sobrecargas que, por supuesto, no tendría sentido, porque a veces T podría ser Objeto, otras veces es de otro tipo. La anulación se volverá dependiente de un objetivo móvil T que es francamente erróneo, especialmente si hubiera múltiples métodos, todos llamados "get" pero con diferentes tipos de parámetros individuales. En tal caso, simplemente no tendría sentido y, en una suposición, eligieron simplemente mantener las cosas simples.

+0

Pero en general, cada genérico es un objeto, ya que cada clase Java se deriva de Object ... – user3001

+0

No del todo, en los anteriores los límites inferiores de T son Object, otras declaraciones miht y a menudo utilizan límites inferiores diferentes. –

7

Se puede ver en el siguiente ejemplo por qué es imposible hacer lo que quiere:

public class Erasure { 

    public void set(Object o) { 
     return; 
    } 

    // method overloading: (which is valid) 
    public void set(String s) { 
     return; 
    } 

    public static class Derived<S> extends Erasure { 

     // Oops... which one am I supposed to override? 
     // (It would actually be overloading if S was a concrete type 
     // that is neither Object nor String.) 
     @Override 
     public void set(S o) { // does not compile 
     super.set(o); 
     } 
    } 
} 

La solución a su problema es que Erasure debe haber una clase parametrizada.

1

Considere un caso en el que tenga un getter y un setter anulados como genéricos.

Derived<String> d = new Derived<String(); 
Erasure e = d; 
e.set(new Object()); 
String s = d.get(); //Class cast exception 

El principio fundamental de los genéricos es que una excepción de difusión clase sólo puede suceder si hay o bien (a) una conversión explícita o (b) una advertencia. Si se le permitiera hacer lo que quería, lo anterior arrojaría una excepción sin ninguno de los dos.

Cuestiones relacionadas