"Olá, amigo! O tópico da lição de hoje é ampliar e restringir conversões de tipos. Você aprendeu sobre ampliar e restringir tipos primitivos há muito tempo. No nível 10. Hoje vamos falar sobre como funciona para tipos de referência, ou seja, instâncias de classes”.
Na verdade, é tudo bem simples. Imagine a cadeia de herança de uma classe: a classe, seu pai, o pai do pai etc., até a classe Object. Como uma classe contém todos os métodos membros da classe que ela herda , uma instância da classe pode ser salva em uma variável cujo tipo é o de qualquer um de seus pais.
Aqui está um exemplo:
Código | Descrição |
---|---|
|
Aqui temos três declarações de classe: Animal, Cat e Tiger. Gato herda Animal. E Tiger herda Cat. |
|
Um objeto Tiger sempre pode ser atribuído a uma variável cujo tipo é o de um de seus ancestrais. Para a classe Tiger, são Cat, Animal e Object. |
Agora vamos dar uma olhada nas conversões de ampliação e restrição.
Se uma operação de atribuição nos faz mover para cima na cadeia de herança (em direção à classe Object), então estamos lidando com uma conversão de ampliação (também conhecida como upcasting). Se descermos na cadeia em direção ao tipo do objeto, será uma conversão de estreitamento (também conhecida como downcasting).
Subir na cadeia de herança é chamado de alargamento, porque leva a um tipo mais geral. No entanto, ao fazer isso, perdemos a capacidade de invocar os métodos adicionados à classe por meio de herança.
Código | Descrição |
---|---|
|
Ao restringir o tipo, você precisa usar um operador de conversão de tipo, ou seja, realizamos uma conversão explícita.
Isso faz com que a máquina Java verifique se o objeto realmente herda o tipo para o qual queremos convertê-lo. Essa pequena inovação produziu uma redução múltipla no número de erros de conversão de tipos e aumentou significativamente a estabilidade dos programas Java. |
Código | Descrição |
---|---|
|
Melhor ainda, use uma instância de verificação |
|
E aqui está o porquê. Dê uma olhada no exemplo à esquerda.
Nós (nosso código) nem sempre sabemos com que tipo de objeto estamos trabalhando. Pode ser um objeto do mesmo tipo da variável (Animal), ou qualquer tipo descendente (Gato, Tigre). Considere o método doAllAction. Funciona corretamente, independentemente do tipo de objeto passado. Em outras palavras, funciona corretamente para todos os três tipos: Animal, Gato e Tigre. |
|
Aqui temos três operações de atribuição. Todos eles são exemplos de conversões ampliadas.
O operador type cast não é necessário aqui, porque nenhuma verificação é necessária. Uma referência de objeto sempre pode ser armazenada em uma variável cujo tipo é um de seus ancestrais. |
"Ah, o penúltimo exemplo deixou tudo claro: por que a verificação é necessária e por que a conversão de tipo é necessária."
"Espero que sim. Quero chamar sua atenção para este fato:"
Nada disso faz com que um objeto mude de forma alguma! A única coisa que muda é o número de métodos disponíveis para serem chamados em uma determinada variável de referência.
Por exemplo, uma variável Cat permite chamar os métodos doAnimalActions e doCatActions. Ele não sabe nada sobre o método doTigerActions, mesmo que aponte para um objeto Tiger.
"Sim, eu entendo. Foi mais fácil do que eu pensei que seria."
GO TO FULL VERSION