Implementação “ilegal” do método genérico: Por que não recebo nenhum erro de compilação?

8

Eu tenho uma interface que contém um método com esta assinatura:

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

Basicamente, MergePropertyé uma classe que NÃO implementa RestartApplicante RestartApplicanté uma interface funcional que contém um método que realmente não importa para a compreensão desse problema.

Aqui está o problema. Quando crio uma classe implementando essa interface, o Java permite que eu execute sem nenhum erro de compilação o seguinte 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, não respeito as restrições da implementação lá. Dada esta assinatura, a lista eu voltar usando Arrays.asList(...)faz não precisa conter elementos que implementam RestartApplicant. Lembre-se, MergePropertynão implementa RestartApplicant. Portanto, isso provavelmente causará algum erro de conversão em algum lugar.

Ainda assim, recebo um aviso:

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>

Minha pergunta é: por que só recebo um aviso? Parece-me que não deveria ser capaz de compilar meu código. Existe alguma razão específica para isso?

Desde já, obrigado.

EDITAR

Depois de brincar um pouco com o meu código, percebi que se eu movesse a "declaração genérica" ​​para o nível da classe, o que levaria a:

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

em vez de apenas

interface MyInterfacePreviouslyDescribed<T>

e obviamente

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

ao invés de

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

na verdade, recebo um erro de compilação se tentar a mesma implementação "ilegal" de antes. Parece ainda mais estranho ...

Akami
fonte

Respostas:

2

Você pode até fazer:

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

no primeiro caso. Isso ocorre porque o método substituído não é genérico e será apagado para isso List. Por que isso é permitido? Francamente, não sei, pode ser algo a ver com compatibilidade com versões anteriores.

No seu segundo exemplo, parece que realmente deveria ser:

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

e na implementação você está forçando os tipos a serem corretos. Na verdade, o segundo exemplo é o intuitivo - pois não compila; e isso é esperado. O primeiro, por outro lado, conta com alguma regra de compatibilidade para métodos não genéricos que permite substituir a mesma eliminação.

Eugene
fonte
Interessante. O segundo exemplo parece realmente mais intuitivo, afinal. E sim, o "T" que faltava no último foi um erro de digitação
Akami 29/10/19