Implementación "ilegal" del método genérico: ¿Por qué no obtengo ningún error de compilación?

8

Tengo una interfaz que contiene un método con esta firma:

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

Básicamente, MergePropertyes una clase que NO se implementa RestartApplicant, y RestartApplicantes una interfaz funcional que contiene un método que realmente no importa para comprender este problema.

Aquí está el truco. Cuando creo una clase que implementa esta interfaz, Java me permite ejecutar sin ningún error de compilación el siguiente código:

public class MyImplementation implements MyInterfacePreviouslyDescribed {

    @Override
    public List<MergeProperty<MathObject>> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }
}

Obviamente, no respeto las restricciones de la implementación allí. Teniendo en cuenta esta firma, la lista vuelvo utilizando Arrays.asList(...)no no necesitan contener elementos que implementan RestartApplicant. Recuerde, MergePropertyno se implementa RestartApplicant. Por lo tanto, esto probablemente terminará causando algún error de transmisión en alguna parte.

Aún así, recibo una advertencia:

Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>

Mi pregunta es: ¿por qué solo recibo una advertencia? Me parece que no debería poder compilar mi código. ¿Hay alguna razón particular para eso?

Gracias por adelantado.

EDITAR

Después de jugar un poco con mi código, pensé que si movía la "declaración genérica" ​​al nivel de la clase, lo que conduciría a:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant>

en lugar de solo

interface MyInterfacePreviouslyDescribed<T>

y obviamente

List<P> loadPropertiesFrom(T p1, T p2);

en vez de

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

entonces obtengo un error de compilación si intento la misma implementación "ilegal" que antes. Parece aún más extraño ...

Akami
fuente

Respuestas:

2

Incluso puedes hacer:

    @Override
    public List<String> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }

en el primer caso. Esto se debe a que el método reemplazado no es genérico y la eliminación de estos lo será List. ¿Por qué está permitido esto? Francamente, no sé, puede tener algo que ver con la compatibilidad con versiones anteriores.

En su segundo ejemplo, parece que realmente debería ser:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant> {

y en la implementación estás obligando a los tipos a ser correctos. En realidad, el segundo ejemplo es intuitivo, ya que no se compila; Y eso se espera. El primero, por otro lado, se basa en alguna regla de compatibilidad para métodos no genéricos que permite anular el mismo borrado.

Eugene
fuente
Interesante. El segundo ejemplo parece más intuitivo después de todo. Y sí, la "T" que faltaba en este último era un error tipográfico
Akami