2011-03-28 9 views
8

Me encontré con esto hoy y lo único que puedo pensar es que este es un error en el compilador de Java. El siguiente código se compila, pero ciertamente parece incorrecto (ya que testMethod tiene una firma differenet en el elemento secundario pero anula el elemento principal) y lanzará excepciones de lanzamiento de clase en el tiempo de ejecución.Agregar un genérico le permite anular un método con un tipo de devolución diferente?

public interface TestInterface<T> { 
    public List<String> testMethod(); // <-- List<String> 
} 
public class TestClass implements TestInterface { 
    @Override 
    public List<Integer> testMethod() { // <-- List<Integer> overriding List<String>!! 
     return Collections.singletonList(1); 
    } 
} 

Y el uso de la estructura anterior:

public void test() { 
    TestInterface<Boolean> test = new TestClass(); 
    List<String> strings = test.testMethod(); 
    for (String s : strings) { 
    System.out.println(s); 
    } 
} 

Todo esto compila bien, pero obviamente habrá lanzar excepciones elenco de clase si lo ejecuta.

Si quita <T> de TestInterface, o de relleno en T en la línea TestClass implements TestInterface<T> entonces el código ya no se compilará, lo cual tiene sentido. Imo <T> no debería tener relación con la compilación de testMethod ya que no forma parte de ese método. Tal vez añadiendo <T> a TestInterface está causando el compilador para escribir-borrar las firmas de método a pesar de que T no participa en esos métodos ...?

¿Alguien sabe lo que está pasando aquí?

+0

+1. Tiene que ser algo muy extraño, realmente extraño, en la implementación genérica –

Respuesta

9

Si instancia una clase genérica como un tipo sin formato, todos los parámetros de tipo genérico que contiene van a ser omitidos por el compilador, por lo que no le da advertencias/errores durante la compilación. Es decir. declarando

public class TestClass implements TestInterface ... 

degrada efectivamente el código en

public interface TestInterface { 
    public List testMethod(); 
} 
public class TestClass implements TestInterface { 
    @Override 
    public List testMethod() { 
     return Collections.singletonList(1); 
    } 
} 

que de hecho compila bien.

Un problema similar se publicó hace un par de semanas, the answer to which indicando que no es un error del compilador, sino una decisión de diseño deliberada para la compatibilidad con versiones anteriores.

+0

bien dicho, "Borrar" es la palabra clave. Google y verás que el código de bits que sale del código anterior no tiene evidencia de que Generics haya sido usado. – somid3

0

La manera en que yo entiendo es que los genéricos es una cosa lado compilador. Nada sobre la información de tipo genérico se incluye en el archivo de clase, es como un truco de compilación. Por eso, puede entremezclar fácilmente llamadas cargadas genéricas con clases genéricas libres y no hay ningún problema en tiempo de ejecución. Escuché que todo lo de dotnet hace que la información de tipo genérico sea un ciudadano de primera clase dentro del archivo objeto.

Así que de todos modos, estos chicos, obviamente, sabe que su problema mejor que yo, pero se debe considerar que todo lo que está pasando en realidad es la pelusa compilador.

Cuestiones relacionadas