O documento discute conceitos de polimorfismo em Java, incluindo herança, classes abstratas, referências polimórficas e interfaces. Ele explica como interfaces podem definir contratos entre classes e tornar programas mais flexíveis, permitindo que classes adicionem funcionalidades independentemente de suas hierarquias de herança.
3. Introdução
● A herança é só o começo do polimorfismo.
● O polimorfismo fornecerá mais flexibilidade,
clareza e facilidade de manutenção do código.
● O principal personagem é a interface.
● Permite a “programação no geral”.
4. Instanciando um objeto
● 1- Especifique o tipo:
Cao
● 2- Dê um nome a variável:
Cao fido
● 3- Aloque espaço ao objeto:
Cao fido new Cao();
● 4- Conecte a instância à variável:
Cao fido = new Cao();
5. Tipos de polimorfismo
● Polimorfismo de Inclusão:
Animal an = new Gato();
● Polimorfismo Paramétrico:
List<Animal> a = new ArrayList<Animal>();
● Polimorfismo de sobrecarga:
public int soma(int a, int b);
public int soma(int[] nums);
6. Exemplo de Polimorfismo
● Suponha que as classes Cao, Gato e Passaro
estendem a classe Animal.
● Suponha que Animal tenha um método
chamado barulho().
● O polimorfismo ocorre quando o programa
invoca um método por uma variável da
superclasse e a versão correta da subclasse é
chamada.
● Assim, cada animal emitirá o seu som
peculiar.
7. Herança
● Um dos benefícios da herança é que podemos
evitar códigos duplicados os agrupando em
uma única classe.
● Podemos sobrescrever os métodos que
devem ser mais específicos.
9. Árvore de herança
● É permitido:
Gato meuGato = new Gato();
Animal meuCao = new Cao();
● Faz sentido instanciar um animal?
Animal anim = new Animal();
10. Árvore de herança
● Como Animal não é específica o suficiente,
ela não deve ser instanciada.
● Assim, basta torná-la abstrata:
abstract class Animal {
…
}
11. Classes abstratas
● Não é possível instanciá-las, é um erro de
compilação. Exemplo:
Animal a = new Animal(); //Errado
● Podemos instanciar apenas as suas classes
concretas.
Animal b = new Gato(); //Correto
12. Classes abstratas
● Definem apenas parte da implementação, isto
é, métodos que ainda podem ser úteis para as
subclasses.
● Se um método não for genérico o bastante,
então o torne abstrato:
public abstract void mover();
● Métodos abstratos não têm corpo e se uma
classe possuir algum método abstrato, ela
deverá ser abstrata também.
13. Por que usar abstract?
● Não faz sentido uma classe abstrata possuir
todos os métodos implementados porque esse
código genérico não será útil para as
subclasses.
● Abstract apenas define o modelo do objeto.
14. Por que usar abstract?
● Poderemos, então, usar um tipo da
superclasse como argumento, tipo de retorno
ou tipo de matriz de um método.
● Será fácil criar novos subtipos sem ter que
reescrever ou adicionar novos métodos para
lidar com esses novos tipos.
● Protocolo de um método abstrato:
“Todos os subtipos desse tipo têm ESSE
método.”
15. Por que usar abstract?
● Sem um modelo, teríamos de fazer isso para
um método fazer os animais emitirem sons:
public void somAnimal ( Cachorro c ) {…}
16. Por que usar abstract?
● Sem um modelo, teríamos de fazer isso para
um método fazer os animais emitirem sons:
public void somAnimal ( Cachorro c ) {…}
public void somAnimal ( Gato g) {…}
17. Por que usar abstract?
● Sem um modelo, teríamos de fazer isso para
um método fazer os animais emitirem sons:
public void somAnimal ( Cachorro c ) {…}
public void somAnimal ( Gato g) {…}
public void somAnimal ( Passaro p) {…}
● E quanto mais classes surgirem, mais
sobrecarga haverá!
18. Por que usar abstract?
● Com um modelo, faríamos apenas isso:
public void somAnimal ( Animal c ) {…}
● Pois todos os animais emitem som, cada um a
seu modo.
19. Classes abstratas
● Lembre-se que um método abstrato não tem
corpo.
● Você deverá dar um na primeira subclasse
concreta.
● Por exemplo, a classe concreta Passaro deve
implementar todos os métodos abstratos de
Animal.
20. Referências polimórficas
● Ocorre quando uma superclasse “aponta”
para um dos seus subtipos.
Object pets[] = new Object[3];
pets[0] = new Cao();
pets[1] = new Gato();
pets[2] = new Passaro();
● Vantagem: Um mesmo array armazena vários
tipos.
● Desvantagem: quais métodos pets[1] tem?
22. Referências polimórficas
● Para usarmos os métodos específicos, temos
que converter o objeto para o seu tipo mais
específico. Assim:
Gato gt = (Gato) pets[1];
nos dará uma referência ao “gato que está
dentro do objeto”.
25. Referências polimórficas
● Se fizermos
Gato gt = (Gato) pets[0];
teremos uma referência a um Gato?
● Não! Pois pets[0] foi instanciado como um
Cao.
● Isso irá gerar em tempo de execução uma
exceção ClassCastException.
27. Contrato
● As classes Cao, Gato e Passaro são
subclasses de Object.
● A classe Object não define nenhum contrato
com as nossas classes.
● Por isso temos que saber de antemão quem é
quem antes de fazer a conversão.
28. Interface
● Interfaces são classes 100% abstratas.
● A interface irá definir o contrato entre as
classes, isto é, o comportamento mínimo que
elas possuem.
● Assim, você define funcionalidades que outras
classes podem obter, independentemente da
sua árvore de herança.
36. Interface
● É garantido que o retorno é uma classe
concreta de Animal.
37. Interface
● Até agora, vimos como interfaces ajudam a
tornar o programa mais simples.
● Vamos ver como elas podem tornar o
programa flexível.
38. Interface
● Temos a interface Animal e suas três
subclasses.
● Todas com um contrato feito: animais emitem
som e se movem.
● Suponha que queiramos agora que apenas os
cães sejam capazes de correr em uma
competição.
● Isso quer dizer que temos de mudar o
contrato.
39. Interface
● Não podemos adicionar um método correr()
na classe Animal pois afetaria a todos.
● Poderíamos adicionar o método diretamente
na classe Cao!
● Mas perderíamos qualquer relação entre um
cão corredor e um humano corredor (atleta).
40. Interface
● Veja o diagrama de classes para pessoas:
41. Interface
● Ora, se um cão corredor e um atleta tem algo
em comum, as duas classes poderiam
estender uma classe chamada Corredor.
46. Interface
● Agora criamos uma “conexão” entre duas
classes de árvores de herança distintas.
● Podemos pensar nisso como “adicionar a
funcionalidade de correr” ao cão e ao atleta.
47. Interface
● Assim, podemos criar um método que faça
com que os que correm, corram.
public void fazerCorrer(Corredor c) {…}
● Não importa de qual árvore de herança os
objetos pertencem, pois sabemos que os que
vierem poderão correr.
48. Quando usar
● Crie uma classe que não estenda nada
(exceto Object) quando esta não passar no
teste do É-UM.
● Cria uma subclasse para ter uma versão mais
específica de uma classe.
● Crie uma classe abstrata para ter um modelo
para suas subclasses, com algum código
implementado.
49. Quando usar
● Crie uma interface para adicionar
funcionalidades a uma classe.
● Assim, qualquer classe pode usar um
interface, independentemente de sua árvore
de herança.
50. Conclusão
● Classes abstratas fornecem reuso de código,
mas são genéricas demais para serem
instanciadas.
● Interfaces são classes 100% abstratas e criam
o contrato com todos os seus subtipos.
● As interfaces fornecem uma ampla
flexibilidade para uso em tipos de retorno,
parâmetro ou de matriz.