"Amigo, você gosta de baleias?"
"Baleias? Não, nunca ouvi falar delas."
"É como uma vaca, só que maior e que nada. Aliás, as baleias vieram das vacas. Uh, ou pelo menos elas compartilham um ancestral comum. Não importa."
"Ouça. Quero falar sobre outra ferramenta muito poderosa de OOP: o polimorfismo . Ele tem quatro recursos."
1) Substituição do método.
Imagine que você escreveu uma classe "Vaca" para um jogo. Ele tem muitas variáveis e métodos membros. Objetos desta classe podem fazer várias coisas: andar, comer, dormir. As vacas também tocam um sino quando caminham. Digamos que você implementou tudo na classe até os mínimos detalhes.
Então, de repente, o cliente diz que quer lançar um novo nível do jogo, onde todas as ações acontecem no mar, e o personagem principal é uma baleia.
Você começou a projetar a classe Whale e percebeu que ela é apenas um pouco diferente da classe Cow. Ambas as classes usam lógica muito semelhante e você decide usar herança.
A classe Cow é ideal para ser a classe pai: ela já possui todas as variáveis e métodos necessários. Tudo o que você precisa fazer é adicionar a capacidade de nadar da baleia. Mas há um problema: sua baleia tem patas, chifres e um sino. Afinal, a classe Cow implementa essa funcionalidade. O que você pode fazer?
A substituição de método vem em socorro. Se herdarmos um método que não faz exatamente o que precisamos em nossa nova classe, podemos substituir o método por outro.
Como isso é feito? Em nossa classe descendente, declaramos o método que queremos alterar (com a mesma assinatura de método da classe pai) . Em seguida, escrevemos um novo código para o método. É isso. É como se o método antigo da classe pai não existisse.
Veja como funciona:
Código | Descrição |
---|---|
|
Aqui definimos duas classes: Cow e Whale . Whale herda Cow .
A |
|
Este código exibe « I'm a cow » na tela. |
|
Este código exibe « I'm a baleia » na tela |
Após herdar Cow
e sobrescrever printName
, a Whale
classe na verdade possui os seguintes dados e métodos:
Código | Descrição |
---|---|
|
Não sabemos nada sobre nenhum método antigo. |
"Honestamente, era isso que eu esperava."
2) Mas isso não é tudo.
"Suponha que a Cow
classe tenha um printAll
método , que chama os outros dois métodos. Então o código funcionaria assim:"
A tela mostrará:
sou branco
sou uma baleia
Código | Descrição |
---|---|
|
|
|
A tela mostrará: sou branco sou uma baleia |
Observe que quando o método printAll () da classe Cow é chamado em um objeto Whale, o método printName () da Whale será usado, não o da Cow.
O importante não é a classe em que o método está escrito, mas sim o tipo (classe) do objeto no qual o método é chamado.
"Eu vejo."
"Você só pode herdar e substituir métodos não estáticos. Métodos estáticos não são herdados e, portanto, não podem ser substituídos."
Aqui está a aparência da classe Whale depois que aplicamos a herança e sobrescrevemos os métodos:
Código | Descrição |
---|---|
|
Aqui está a aparência da classe Whale depois que aplicamos a herança e sobrescrevemos o método. Não sabemos nada sobre nenhum printName método antigo. |
3) Tipo de fundição.
Aqui está um ponto ainda mais interessante. Como uma classe herda todos os métodos e dados de sua classe pai, um objeto dessa classe pode ser referenciado por variáveis da classe pai (e o pai do pai, etc., até a classe Object). Considere este exemplo:
Código | Descrição |
---|---|
|
A tela mostrará: eu sou branco. |
|
A tela mostrará: eu sou branco. |
|
A tela mostrará: Whale@da435a. O método toString() é herdado da classe Object. |
"Coisa boa. Mas por que você precisa disso?"
"É um recurso valioso. Você entenderá mais tarde que é muito, muito valioso."
4) Ligação tardia (despacho dinâmico).
Aqui está o que parece:
Código | Descrição |
---|---|
|
A tela mostrará: eu sou uma baleia. |
|
A tela mostrará: eu sou uma baleia. |
Observe que não é o tipo da variável que determina qual método printName específico chamamos (o da classe Cow ou Whale), mas sim o tipo de objeto referenciado pela variável.
A variável Cow armazena uma referência a um objeto Whale , e o método printName definido na classe Whale será chamado.
"Bem, eles não acrescentaram isso por uma questão de clareza."
"Sim, não é tão óbvio. Lembre-se desta regra importante:"
O conjunto de métodos que você pode chamar em uma variável é determinado pelo tipo da variável. Mas qual método/implementação específico é chamado é determinado pelo tipo/classe do objeto referenciado pela variável.
"Vou tentar."
"Você vai se deparar com isso constantemente, então você vai entender rapidamente e nunca esquecer."
5) Tipo de fundição.
A conversão funciona de maneira diferente para tipos de referência, ou seja, classes, do que para tipos primitivos. No entanto, as conversões de alargamento e estreitamento também se aplicam a tipos de referência. Considere este exemplo:
Ampliando a conversão | Descrição |
---|---|
|
Uma conversão de ampliação clássica. Agora você só pode chamar métodos definidos na classe Cow no objeto Whale. O compilador permitirá que você use a variável cow apenas para chamar os métodos definidos pelo tipo Cow. |
Conversão estreita | Descrição |
---|---|
|
Uma conversão de restrição clássica com uma verificação de tipo. A variável cow do tipo Cow armazena uma referência a um objeto Whale. Verificamos se esse é o caso e, em seguida, realizamos a conversão de tipo (alargamento). Isso também é chamado de conversão de tipo . |
|
Você também pode executar uma conversão de restrição de um tipo de referência sem verificar o tipo do objeto. Nesse caso, se a variável cow estiver apontando para algo diferente de um objeto Whale, uma exceção (InvalidClassCastException) será lançada. |
6) E agora algo saboroso. Chamando o método original.
Às vezes, ao substituir um método herdado, você não deseja substituí-lo totalmente. Às vezes você só quer adicionar um pouco a ele.
Nesse caso, você realmente deseja que o código do novo método chame o mesmo método, mas na classe base. E o Java permite que você faça isso. É assim que se faz: super.method()
.
aqui estão alguns exemplos:
Código | Descrição |
---|---|
|
|
|
A tela vai mostrar: eu sou branco Isso é falso: eu sou uma vaca eu sou uma baleia |
"Hmm. Bem, isso foi uma lição. Minhas orelhas de robô quase derreteram."
"Sim, isso não é algo simples. É um dos materiais mais difíceis que você encontrará. O professor prometeu fornecer links para materiais de outros autores, para que, se você ainda não entender alguma coisa, possa preencher o formulário lacunas."
GO TO FULL VERSION