Estou apenas aprendendo Java e não sou um programador praticante.
O livro que estou seguindo diz que, ao substituir um método, os tipos de argumento devem ser os mesmos, mas os tipos de retorno podem ser polimorficamente compatíveis.
Minha pergunta é por que os argumentos passados para o método de substituição não podem ser um tipo de subclasse do super-tipo esperado?
No método sobrecarregado, qualquer método que eu chamo no objeto tem a garantia de ser definido no objeto.
Notas sobre duplicatas sugeridas:
A primeira sugestão parece ser sobre hierarquia de classes e onde colocar a funcionalidade. Minha pergunta é mais focada em por que a restrição de idioma existe.
A segunda sugestão explica como fazer o que estou pedindo, mas não por que isso deve ser feito dessa maneira. Minha pergunta está focada no porquê.
fonte
Respostas:
O conceito a que você se refere inicialmente na sua pergunta é chamado de tipos de retorno covariante .
Os tipos de retorno covariantes funcionam porque é suposto que um método retorne um objeto de determinado tipo e os métodos de substituição podem realmente retornar uma subclasse dele. Com base nas regras de subtipagem de uma linguagem como Java, se
S
for um subtipo deT
, então, onde quer queT
apareça, podemos passar umS
.Como tal, é seguro retornar um
S
ao substituir um método que esperava aT
.Sua sugestão de aceitar que uma substituição de um método use argumentos que são subtipos daqueles solicitados pelo método substituído é muito mais complicada, pois leva à insatisfação no sistema de tipos.
Por um lado, pelas mesmas regras de subtipo mencionadas acima, provavelmente já funciona para o que você deseja fazer. Por exemplo
Nada impede que as implementações desta classe recebam qualquer tipo de animal, pois, como tal, ele já atende aos critérios de sua pergunta.
Mas vamos supor que possamos substituir esse método como você sugeriu:
Aqui está a parte engraçada, agora você pode fazer isso:
De acordo com a interface pública,
AnimalHunter
você deve ser capaz de caçar qualquer animal, mas de acordo com sua implementação,MammutHunter
você só aceitaMammut
objetos. Portanto, o método substituído não satisfaz a interface pública. Acabamos de quebrar a solidez do sistema de tipos aqui.Você pode implementar o que deseja usando genéricos.
Então você pode definir seu MammutHunter
E usando covariância e contravariância genéricas, você pode relaxar as regras a seu favor quando necessário. Por exemplo, podemos garantir que um caçador de mamíferos só possa caçar felinos em um determinado contexto:
Supondo
MammalHunter
instrumentosAnimalHunter<Mammal>
.Nesse caso, isso não seria aceito:
Mesmo quando mamutes são mamíferos, isso não seria aceito devido às restrições do tipo contravariante que estamos usando aqui. Portanto, você ainda pode exercer algum controle sobre os tipos para fazer coisas como as que você mencionou.
fonte
O problema não é o que você faz no método de substituição com o objeto fornecido como argumento. O problema é qual é o tipo de argumento que o código usando o seu método pode alimentar ao seu método.
Um método de substituição deve cumprir o contrato do método de substituição. Se o método substituído aceitar argumentos de alguma classe e você o substituir por um método que aceita apenas uma subclasse, ele não cumprirá o contrato. É por isso que não é válido.
Substituir um método por um tipo mais específico de argumento é chamado de sobrecarga . Ele define um método com o mesmo nome, mas com um tipo de argumento diferente ou mais específico. Um método sobrecarregado está disponível além do método original. Qual método é chamado depende do tipo conhecido em tempo de compilação. Para sobrecarregar um método, você deve descartar a anotação @Override.
fonte