2011-12-18 16 views
10

He probado algunas cosas con parámetros acotados en métodos genéricos y descubrí un comportamiento extraño.
Sería genial si alguien pudiera explicar los dos errores en el siguiente fragmento de código.Parámetros enlazados de Java en métodos genéricos

Imagine que hay dos clases Class1 y Class2 ambas se extienden desde un BaseClass. Class2 implementa una interfaz.

En Class1, tengo un método que devuelve una instancia de Class2 de la siguiente manera:

public class Class2 extends BaseClass implements Interface { 

    @Override 
    public void method() { 
     System.out.println("test"); //$NON-NLS-1$ 
    } 
} 

public class Class1 extends BaseClass { 

    public <T extends BaseClass & Interface> T getTwo() { 
     return new Class2(); 
     // Error: Type mismatch: cannot convert from Class2 to T 
    } 

    public static void main(String[] args) { 
     Interface two = new Class1().getTwo(); 
     // Error: Bound mismatch: The generic method getTwo() of type Class1 is 
     // not applicable for the arguments(). The inferred type Interface is 
     // not a valid substitute for the bounded parameter <T extends BaseClass 
     // & Interface> 
     System.out.println(two); 
    } 
} 
+0

Parece que el mal uso de los medicamentos genéricos. En realidad, 'getTwo' debe tener el tipo de devolución simplemente' Class2', o 'BaseClass', o' Interface'. Si 'T' se define solo para un método, el compilador no puede saber qué clase sustituye exactamente a' T' en la línea 'new Class1(). GetTwo()'. Solo sería posible si 'getTwo' tuviera parámetros de entrada de este tipo. – DRCB

Respuesta

5

se produce el primer error de compilación, porque los parámetros de tipo declarados por métodos son especificados por la persona que llama, no la implementación del método . Es decir, dado

class Class3 extends BaseClass implements Interface { ... } 

una persona que llama puede escribir

Class3 c3 = new Class1().<Class3>getTwo(); 

, pero la implementación del método devuelve un Class2, que no es un subtipo de T = Class3.

El segundo error de compilación se produce porque los parámetros de tipo que el llamador no especifica explícitamente se deducen de los argumentos del método y del tipo de la variable a la que se asigna el valor de retorno del método. Esta inferencia falla aquí. La solución habitual, recomendada por la Especificación del lenguaje Java, es especificar explícitamente los parámetros de tipo en tales casos (la inferencia de tipo está pensada como una conveniencia para casos simples, no pretende cubrir todos los casos).

En cuanto a cómo declarar correctamente este parámetro de tipo, necesitaría saber lo que está intentando lograr con estas declaraciones.

+1

+1 Buena respuesta. Creo que la sintaxis sería 'new Class1(). getTwo() 'sin embargo, en su segundo ejemplo de código. –

+0

Oh, por supuesto. Gracias, arreglado. – meriton

+0

Veo el punto del primer error de compilación, pero no estoy seguro del segundo. La llamada 'BaseClass dos = new Class1(). GetTwo();' parece estar bien en mi sistema pero falla en el sistema de un colega y la llamada 'Interfaz dos = new Class1(). GetTwo();' falla mi sistema, también (como se muestra arriba) ... – Marco

4

¿Por qué utilizar genéricos para el método getTwo, cuando sabe es Class2? Basta con hacer esto:

public Class2 getTwo() { 
    return new Class2(); 
} 

Si va a sustituir un método public <T extends BaseClass & Interface> T getTwo(), el compilador le permitirá declara su impl como public Class2 getTwo() cuando su T para su impl es Class2

+0

No tan rápido en esa anulación. En su escenario, estaría anulando un método que podría devolver cualquier T que satisfaga la restricción con uno que devolviera Class2, que no debería permitirse por la misma razón por la que no se permitió el código del OP. No estoy seguro de que Java pueda incluso expresar un tipo de devolución con un cuantificador existencial. –

Cuestiones relacionadas