Java com café: Regras de Cast - Java

Regras de Cast - Java

Olá! Hoje vamos nos aprofundar um pouco mais nas conversões de tipos. Num outro post eu cheguei a abordar o assunto, porém faltou um esclarecimento maior sobre erros que podem ocorrer. Conversões de tipos no Java podem ser um pouco confusas, pois temos regras para tempo de compilação e de execução. Por exemplo, temos duas classes:
public class Veiculo {

public static void main(String[] args) {

}

}

class Carro extends Veiculo {

}

Um dos casos mais comuns é a conversão ampliadora ou upcasting, onde um tipo mais genérico pode referenciar outro mais específico (um subtipo):
Veiculo v = new Carro();

Temos uma variável de referência do tipo Veiculo que aponta para um objeto do tipo Carro. Sabemos que o contrário não pode ser feito e causa erro de compilação, porque Carro É-UM Veiculo, mas Veiculo NÃO-É-UM Carro.
A conversão ampliadora é totalmente segura, não causará erros de compilação nem execução. E também não exige nenhuma declaração explícita. Simplesmente fazemos a referência e o compilador entenderá que é seguro uma variável do tipo Veiculo referenciar um objeto Carro, pois Veiculo pode fazer coisas que Carro faz. Isso porque Carro herdou estes comportamentos. Na verdade Carro pode fazer ainda mais coisas, porém como Veiculo não sabe dessas coisas, esse tipo de conversão limita os comportamentos de Carro. Agora somente métodos de Veiculo podem ser chamados. Lembre-se que a variável de referência é quem diz quais métodos poderão ser chamados.

Vamos continuar e ver uma conversão redutora, ou downcasting:
Carro c = v;

Veja que estamos indo pra baixo na árvore de herança agora. Tentamos fazer com que a variável de refência do tipo Veiculo (usada anteriomente para referenciar Carro), seja atribuída a outra variável do tipo Carro, fazendo com que as duas apontem para o mesmo objeto. Um pouco confuso mas veja como funciona:

Antes fizemos isto:

Veiculo -> Carro


Agora estamos tentando isto:

Carro = Veiculo -> Carro

Essa conversão não pode ser feita implicitamente, como no upcasting. O código anterior não compila, mas como sabemos que a variável v aponta pra um objeto do tipo Carro, podemos fazer a conversão explicitamente:

Carro = (Carro)Veiculo -> Carro

Isto é:
Carro c = (Carro)v;

Isto funcionou porque v faz referência a um objeto Carro. Então é seguro a referência Veiculo para Carro. Lembre-se que o tipo de objeto sendo refenciado é que determina se a conversão poderá ser feita. Mas e se o objeto referenciado não fosse Carro? Agora fica interessante porque o compilador lava suas mãos. Portanto, o seguinte código vai compilar:
Veiculo v1 = new Veiculo(); //Objeto Veiculo

Carro c1 = (Carro)v1;

Mas como o que estamos tentando fazer é isto:

Carro = (Carro)Veiculo -> Veiculo!!


Quando executamos o código, a seguinte mensagem será exibida:

Exception in thread "main" java.lang.ClassCastException:
Veiculo cannot be cast to Carro

Outros códigos serão executados normalmente, mas quando tentar a conversão acima, a exceção vai finalizar o programa. Isso nos mostra que só podemos fazer downcasting se o objeto sendo refenciado for do tipo da variável que vai fazer a referência. O compilador não sabe se estamos fazendo isso errado, mas podemos nos prevenir de duas formas. Uma é usando o operador instanceof:
Veiculo v1 = new Veiculo();

if (v1 instanceof Carro) {
    Carro c1 = (Carro) v1;
}else
    System.out.println("Não foi possível...");

Outra é tratando a exceção:
try{
    Carro c1 = (Carro)v1;
}catch (ClassCastException e) {
    System.out.println("Não foi possível...");
}

Com isso espero ter esclarecido dúvidas sobre erros de compilação e execução causados pelas conversões.
Por hoje é só pessoal! Bons estudos..

5 comentários: