Pode parecer um assunto batido, mas será que não tem uns "peguinhas" para quem está de olho no exame para certificação?
Convertendo variáveis de referência.
Este assunto tem uma relação com polimorfismo. A mágica do polimorfismo está em você poder referenciar um tipo mais específico com uma variável de um tipo mais genérico.
Isto é possível porque o compilador verifica a árvore de herança das classes envolvidas neste processo, veja:
public class Veiculo{
public void informaLotacao(){
System.out.println("Um motorista.");
}
}
public class Ferrari extends Veiculo{
public void informaLotacao(){
System.out.println("Um motorista e um passageiro.");
}
public void informaPotencia(){
System.out.println("460 cavalos.");
}
}
public class Onibus extends Veiculo{
public void informaLotacao(){
System.out.println("Um motorista e trinta e dois passageiros.");
}
public void informaCombustivel(){
System.out.println("Diesel.");
}
}
public class TestaVeiculo{
public static void main(String[] args){
Veiculo ferrari = new Ferrari();
Veiculo onibus = new Onibus();
System.out.println("Uma ferrari tem espaço para " + ferrari.informaLotacao() + " e possui " + ferrari.informaPotencia());
System.out.println("Um ônibus tem espaco para " + onibus.informaLotacao() + " e funciona com " + onibus.informaCombustivel());
}
}
Ao executar TestaVeiculo que saída você espera receber?
Na verdade, vai acontecer um erro de compilação dizendo cannot find symbol. Isso porque as referências são do tipo Veiculo, que não possui o metodo informaPotencia() e nem informaCombustivel().
Entenda que você só pode chamar os métodos que o tipo da sua variável de referência expõe para você, mesmo que seja uma referência para uma instância de um tipo mais especializado, com mais métodos.
Para acessar os métodos do tipo especializado temos primeiro que converter os tipos, veja:
public class TestaVeiculo{
public static void main(String[] args){
Veiculo ferrari = new Ferrari();
Veiculo onibus = new Onibus();
Ferrari ferrariConvertida = (Ferrari) ferrari;
Onibus onibusConvertido = (Onibus) onibus;
System.out.println("Uma ferrari tem espaço para " + ferrariConvertida.informaLotacao() + " e possui " + ferrariConvertida.informaPotencia());
System.out.println("Um ônibus tem espaco para " +
onibusConvertido.informaLotacao() + " e funciona com " +
onibusConvertido.informaCombustivel());
}
}
Agora você fez as pazes com o compilador, realizando o cast (conversão) de sua referência generica para um tipo mais específico, que expõe os métodos que você quer usar. Tudo certo! Mas pense comigo: já que o compilador olha apenas para a árvore de herança, o que aconteçe em uma situação assim:
public class TestaVeiculo{
public static void main(String[] args){
Veiculo ferrari = new Veiculo();
Veiculo onibus = new Veiculo();
Ferrari ferrariConvertida = (Ferrari) ferrari;
Onibus onibusConvertido = (Onibus) onibus;
System.out.println("Uma ferrari tem espaço para " + ferrariConvertida.informaLotacao() + " e possui " +
ferrariConvertida.informaPotencia());
System.out.println("Um ônibus tem espaco para " +
onibusConvertido.informaLotacao() + " e funciona com " +
onibusConvertido.informaCombustivel());
}
}
Bom neste caso, você prova que o compilador só olha para a árvore de herança, porque ele não vai reclamar de nada. Entretanto, ao executar o código você vai receber um java.lang.ClassCastException, porque as variáveis de referência ferrari e onibus agora são do tipo Veiculo e um tipo generalizado não cabe em um tipo especializado, ou seja, Ferrari é um Veiculo, mas Veiculo, não necessariamente, é uma Ferrari. Ou ainda, Veiculo pode ser um Onibus, que é bem diferente de uma Ferrari, concorda?
Saber o que não compila e o que compila e não roda é fundamental para o exame.
Forte abraço e até a próxima.
Mauricio da Silva Marinho.