quinta-feira, 6 de maio de 2010

[Java] Definir herança, polimorfismo, sobrecarga, sobrescrita e invocação de método virtual (parte 2/3)


Polimorfismo

Em POO (programação orientada a objetos), o polimorfismo é a capacidade de permitir que referências de tipos de classes mais abstratas representem o comportamento das classes concretas que elas referenciam. Enquanto um objeto tem apenas uma forma (aquela que é dada quando ele é construído) uma variável é polimórfica porque pode referenciar a objetos de diferentes formas. A linguagem de programação Java, como a maioria das linguagens orientadas a objeto, permite o polimorfismo. Utilizando o exemplo do post anterior:

Animal anim = new Cavalo();

Usando a variável acima anim da forma que está você só conseguirá acessar as partes do objeto que forem parte de Animal, as partes que forem específicas de Cavalo estaram escondidas. Isto acontece porque para o compilador a variável anim é um Animal e não um Cavalo. Assim o exemplo a seguir não é válido:

anim.raca = "Mangalarga";

Coleções heterogêneas

Em Java também é possível criar coleções de objetos que tem uma classe em comum. Essas coleções são chamadas de coleções homogêneas. Exemplo:
Agenda[] nome = new Agenda[3];
nome[0] = new Agenda("Carina");
nome[1] = new Agenda("Cristina");
nome[2] = new Agenda("Juliana");
A linguagem de programação Java tem uma classe chamada Object e todas as classes em Java extendem essa classe Object. Assim você pode fazer coleções de todos os tipos de elementos devido ao polimorfismo. Essas coleções de vários tipos são chamadas coleções heterogêneas. Exemplo:
Animal[] habitat = new Animal[3];
habitat[0] = new Peixe();
habitat[1] = new Cavalo();
habitat[2] = new Aguia();
Pode parecer estranho criar um objeto do tipo Cavalo e usar uma variável do tipo Animal para referenciá-lo, mas isto é possivel em Java e você poderá querer ter este efeito.

Argumentos Polimórficos

Um método pode ser escrito para receber como parâmetro um objeto de uma superclasse, no nosso exemplo a classe Animal, e receber sem problemas qualquer objeto da subclasse que foi declarada como parâmetro do método. Assim, em nosso exemplo, podemos escrever um método que recebe como parâmetro um objeto da classe Animal e receber na verdade um objeto da classe Cavalo como mostra o exemplo:
// Na classe Animal
public String determinaPorte (Animal a){
//Determina a partir do pesoMedio do animal qual é seu porte
}
...

// Em alguma parte de outra classe

Cavalo c = new Cavalo();
...
String porte = determinaPorte (c);
Esta chamada ao método determinaPorte é legal porque Cavalo é um Animal.

Operador instanceof

Sabendo que é possivel passar como parâmetros objetos que sejam filhos daquele determinado na escrita do método, algumas vezes é necessário a determinação de que tipo de objeto é realmente aquele. Para esse propósito temos o operador instanceof. Levando em consideração o diagrama de classe do post anterior, veja o exemplo abaixo:
public void metodoExemplo (Animal a){
if (a instanceof Cavalo){
// Faz alguma coisa com Cavalo
}
if (a instanceof Peixe){
// Faz alguma coisa com Peixe
}
if (a instanceof Aguia){
// Faz alguma coisa com Aguia
}
else {
// Faz alguma coisa com Animal
}
}

Conversão de Objetos

Em circunstâncias que você recebeu uma referência para uma classe pai e já foi determinado usando o operador instanceof que o objeto é, na verdade, uma subclasse particular. É possível restorar a funcionalidade completa daquele objeto utilizando a conversão de objetos (casting). Veja o exemplo abaixo:
public void metodoExemplo (Animal a){
if (a instanceof Cavalo){
Cavalo c = (Cavalo)a; // Casting
}
// Restante do método
}
Como já explicado, se não for feito o cast, ao se tentar executar a.getRaca() iria retornar em erro, pois para o compilador o método getRaca() não é acessível na classe Animal.

Observações sobre a conversão de objetos:
  • A conversão de um objeto de uma subclasse para o tipo de sua classe pai (de baixo para cima) é sempre permitida e de fato não necessita de cast explícito.
  • Para conversões "de cima para baixo" (conversão de um objeto de uma classe pai para uma subclasse) só é possível se a classe destino for alguma subclasse da classe atual.
  • Se o compilador permite o cast, então o tipo do objeto é checado em tempo de execução.

Nenhum comentário:

Postar um comentário