sencillos - Java herencia de método genérico y reglas de anulación
herencia simple en java (5)
Tengo una clase abstracta que tiene un método genérico y quiero anular el método genérico sustituyendo tipos específicos para el parámetro genérico. Entonces en el pseudo-código tengo lo siguiente:
public abstract class GetAndParse {
public SomeClass var;
public abstract <T extends AnotherClass> void getAndParse(T... args);
}
public class Implementor extends GetAndParse {
// some field declarations
// some method declarations
@Override
public <SpecificClass> void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
¿Pero por alguna razón no puedo hacer esto? ¿Estoy haciendo algún tipo de error de sintaxis o este tipo de herencia y anulación no está permitido? Específicamente recibo un error sobre @Override
porque el eclipse IDE sigue recordándome que getAndParse
implementar getAndParse
.
Así es como quiero que funcione el código anterior. En algún otro lugar de mi código hay un método que espera instancias de objetos que implementen GetAndParse
que significa específicamente que tienen un método getAndParse
que puedo usar. Cuando llamo a getAndParse
en esa instancia, el compilador comprueba si he usado instancias específicas de T
de la manera adecuada, por lo que, en particular, T
debería extender AnotherClass
y debería ser SpecificClass
.
Eso se convierte en una tontería cuando alguien hace referencia al tipo GetAndParse e intenta llamar al método getAndParse. Si Cat y Dog extienden AnotherClass. Debo esperar poder llamar a GetAndParse # getAndParse con un gato o un perro. ¡Pero la implementación ha tratado de restringirlo y hacerlo menos compatible!
Está viendo este problema debido al concepto llamado "Borrado" en Java Generics. Java usa "borrado" para admitir la compatibilidad con versiones anteriores. es decir, código Java que no usaba genéricos.
Procedimiento de borrado:
El compilador primero hará una verificación de tipo y luego eliminará (borrará) todos los parámetros de tipo tanto como sea posible, y también insertará TypeCasting donde sea necesario.
ejemplo:
public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass);
se convertirá
public abstract void getAndParse(AnotherClass paramAnotherClass);
En la clase "Implementor.java",
El código
public <SpecificClass> void getAndParse(T paramAnotherClass)
se convertirá
public void getAndParse(SpecificClass paramAnotherClass){ }
el compilador verá que no ha implementado el método abstracto correctamente. Hay un desajuste de tipo entre el método abstracto y el método implementado. Es por eso que estás viendo el error.
Más detalles se pueden encontrar aquí. http://today.java.net/pub/a/today/2003/12/02/explorations.html
Lo que tenemos aquí es dos métodos diferentes con parámetros de tipo individuales cada uno.
public abstract <T extends AnotherClass> void getAndParse(Args... args);
Este es un método con un parámetro de tipo denominado T y delimitado por AnotherClass
, lo que significa que cada subtipo de AnotherClass
está permitido como parámetro de tipo.
public <SpecificClass> void getAndParse(Args... args)
Este es un método con un parámetro de tipo llamado SpecificClass
, delimitado por Object
(lo que significa que cada tipo está permitido como parámetro de tipo). ¿De verdad quieres esto?
¿El parámetro de tipo se usa dentro de Args
? Creo que el problema estaría allí.
Editar:
El significado de
public abstract <T extends AnotherClass> void getAndParse(T... args);
es que la persona que llama del método puede decidir con qué parámetro de tipo quiere llamar al método, siempre que este sea algún subtipo de AnotherClass
. Esto significa que, en efecto, se puede llamar al método con cualquier objeto de tipo AnotherClass
.
Como la persona que llama puede decidir el parámetro de tipo, no puede en una subclase reducir el tipo de parámetro a SpecificClass
; esto no sería una implementación del método, sino otro método con el mismo nombre (sobrecarga).
Tal vez quieras algo como esto:
public abstract class GetAndParse<T extends AnotherClass> {
public SomeClass var;
public abstract void getAndParse(T... args);
}
public class Implementor extends GetAndParse<SpecificClass> {
// some field declarations
// some method declarations
@Override
public void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
Ahora el método getAndParse
implementa el método de la clase padre.
No puede anular al tipo específico T porque de hecho (en el nivel de bytecode si lo desea) solo hay un método getAndParse debido al borrado de tipo (vea otra respuesta):
public abstract void getAndParse(AnotherClass... args); // (1)
Para cada tipo de T, se usa el mismo método.
Puedes sobrecargarlo (creo):
public void getAndParse(SpecificClass... args); // (2)
pero este no será un método diferente de (1) y no se llamará por código genérico:
T x = whatever;
object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass
No, no es válido ¿Qué pasaría si alguien con una referencia GetAndParse
llamara con una clase diferente que extendiera AnotherClass
?