17/9/15
1
Programação III Polimorfismo
(cont.) Classes abstratas
Interfaces
Prof. João Paulo A. Almemida
Slides adaptados do Prof. Vítor Silva Souza, com permissão
Agenda • Polimorfismo • Classes abstratas • Interfaces • Coleções
Julho 2013 Desenvolvimento OO com Java 2
Exemplo de polimorfismo
Julho 2013 Desenvolvimento OO com Java 3
class Forma { public void desenhar() { System.out.println("Forma"); } } class Circulo extends Forma { public void desenhar() { System.out.println("Círculo"); } } class Quadrado extends Forma { /* ... */ } class Triangulo extends Forma { /* ... */ }
Exemplo de polimorfismo
Julho 2013 Desenvolvimento OO com Java 4
public class Teste { private static void desenha(Forma[] fs) { for (int i = 0; i < fs.length; i++) fs[i].desenhar(); } public static void main(String[] args) { Forma[] formas = new Forma[] { new Circulo(), new Forma(), new Quadrado(), new Triangulo() }; desenha(formas); } }
Exemplo de polimorfismo • Ampliação (upcas&ng) é a conversão implícita de uma subclasse para uma superclasse:
Julho 2013 Desenvolvimento OO com Java 5
class Teste { public static void inverter(Forma f) { System.out.println("Inverte " + f); } public static void main(String[] args) { Circulo c = new Circulo(); inverter(c); // Upcasting! Forma f = new Quadrado(); // Upcasting! } }
Incrementando o exemplo • O compilador realmente não sabe qual é o Opo. Veja um exemplo com geração aleatória:
Julho 2013 Desenvolvimento OO com Java 6
public static void main(String[] args) { Forma f = null; switch((int)(Math.random() * 3)) { case 0: f = new Circulo(); case 1: f = new Quadrado(); case 2: f = new Triangulo(); default: f = new Forma(); } f.desenhar(); }
17/9/15
2
Amarração • No entanto, se trabalhamos com Forma, como saber qual implementação executar quando chamamos um método?
Julho 2013 Desenvolvimento OO com Java 7
public class Teste { private static void desenha(Forma[] fs) { for (int i = 0; i < fs.length; i++) fs[i].desenhar(); } }
fs[i] é do tipo Forma. Chamar sempre Forma.desenhar()?
Amarração tardia • Em linguagens estruturadas, os compiladores realizam amarração em tempo de compilação;
• Em linguagens OO com polimorfismo, não temos como saber o Opo real do objeto em tempo de compilação;
• A amarração é feita em tempo de execução, também conhecida como: – Amarração tardia; – Amarração dinâmica; ou – Late binding.
Julho 2013 Desenvolvimento OO com Java 8
Amarração tardia
Julho 2013 Desenvolvimento OO com Java 9
Quando usar • Amarração dinâmica é menos eficiente; • No entanto, ela que permite o polimorfismo; • Java usa sempre amarração dinâmica; • A exceção: se um método é final, Java usa amarração estáOca (pois ele não pode ser sobrescrito); – (e obviamente se o método for staOc)
• Você não pode escolher quando usar um ou outro. É importante apenas entender o que acontece.
Julho 2013 Desenvolvimento OO com Java 10
Sobrescrita vs. sobrecarga • Cuidado para não confundir:
Julho 2013 Desenvolvimento OO com Java 11
class Forma { public void aumentar(int t) { System.out.println("Forma.aumentar()"); } } class Linha extends Forma { // Foi feita sobregarga e não sobrescrita! public void aumentar(double t) { System.out.println("Linha.aumentar()"); } }
Sobrescrita vs. sobrecarga • A confusão gera um erro muito diecil de descobrir:
Julho 2013 Desenvolvimento OO com Java 12
public class Teste { public static void main(String[] args) { Linha l = new Linha(); l.aumentar(10); // Forma.aumentar() } }
17/9/15
3
Sobrescrita vs. sobrecarga • Anotação ajuda a idenOficar o problema
Julho 2013 Desenvolvimento OO com Java 13
class Forma { public void aumentar(int t) { System.out.println("Forma.aumentar()"); } } class Linha extends Forma { // Foi feita sobregarga e não sobrescrita! @Override public void aumentar(double t) { System.out.println("Linha.aumentar()"); } }
Classes e métodos abstratos • Algumas vezes classes no topo da hierarquia são muito gerais: – O que é uma forma? – Como se desenha uma forma? – Como se aumenta uma forma?
• Tais operações não fazem senOdo. Queremos apenas definir que elas existam, mas não implementá-‐las;
• A solução: métodos abstratos.
Julho 2013 Desenvolvimento OO com Java 14
Classes e métodos abstratos • Uma classe que possui métodos abstratos deve ser declarada como abstrata:
Julho 2013 Desenvolvimento OO com Java 15
abstract class Forma { public abstract void desenhar(); } class Circulo extends Forma { public void desenhar() { System.out.println("Círculo"); } }
Classes abstratas • Não permitem criação de instâncias (objetos):
– Um método abstrato não possui implementação, portanto não pode ser chamado;
– Podemos ter classes abstratas sem métodos abstratos, mas não o contrário.
• Para ser úOl, deve ser estendida: – Suas subclasses devem implementar o método ou declararem-‐se como abstratas.
• Servem para definir interfaces e prover algumas implementações comuns.
Julho 2013 Desenvolvimento OO com Java 16
Classes e métodos abstratos • Algumas regras:
– Métodos estáOcos não podem ser abstratos; – Construtores não podem ser abstratos; – Classes abstratas podem ter construtores (lembre-‐se que são chamados pelas subclasses!);
– Métodos abstratos não podem ser privados.
Julho 2013 Desenvolvimento OO com Java 17
Classes e métodos abstratos
Julho 2013 Desenvolvimento OO com Java 18
// Classe abstrata pura. abstract class Forma { public abstract void desenhar(); public abstract void aumentar(int t); } // Classe abstrata. abstract class Poligono extends Forma { private int lados; public Poligono(int lados) { this.lados = lados; } public int getLados() { return lados; } public abstract void pintar(int cor); }
17/9/15
4
Classes e métodos abstratos
Julho 2013 Desenvolvimento OO com Java 19
// Classe concreta. class Retangulo extends Poligono { public Retangulo() { super(4); } public void desenhar() { System.out.println("Retangulo.desenhar"); } public void aumentar(int t) { System.out.println("Retangulo.aumentar"); } public void pintar(int cor) { System.out.println("Retangulo.pintar"); } }
Polimorfismo com java.lang.Object • Relembrando a interface comum a todas as classes escritas em Java: – clone(): cria uma cópia do objeto (uso avançado); – equals(Object o): verifica se objetos são iguais; – finalize(): chamado pelo GC (não é garanOa); – getClass(): retorna a classe do objeto; – hashCode(): função hash; – notify(), notifyAll() e wait(): para uso com threads;
– toString(): converte o objeto para uma representação como String.
Julho 2013 Desenvolvimento OO com Java 20
O método equals() • Compara dois objetos. Retorna true se forem iguais, false se não forem;
• Permitem polimorfismo em grande escala: – Podemos criar uma classe conjunto que armazena objetos de qualquer classe, desde que sejam objetos diferentes;
– Podemos implementar um método que permite dizer se um objeto está no conjunto, se um conjunto está conOdo em outro, etc.
Julho 2013 Desenvolvimento OO com Java 21
O método equals()
Julho 2013 Desenvolvimento OO com Java 22
class Valor { int i; public Valor(int i) { this.i = i; } } public class Teste { public static void main(String[] args) { Integer m = new Integer(100); Integer n = new Integer(100); System.out.println(m == n); // false System.out.println(m.equals(n)); // true Valor v = new Valor(100); Valor u = new Valor(100); System.out.println(v.equals(u)); // false } }
O método equals()
Julho 2013 Desenvolvimento OO com Java 23
class Valor { int i; public Valor(int i) { this.i = i; } public boolean equals(Object o) { return (o instanceof Valor) && (((Valor)o).i == i); } } public class Teste { public static void main(String[] args) { Valor v = new Valor(100); Valor u = new Valor(100); System.out.println(v.equals(u)); // true } }
O método toString() • Retorna uma representação em String do objeto em questão;
• Permite polimorfismo em grande escala: – Se quisermos imprimir um objeto de qualquer classe, ele será chamado;
– Se quisermos concatenar um objeto de qualquer classe com uma String, ele será chamado.
Julho 2013 Desenvolvimento OO com Java 24
17/9/15
5
O método toString()
Julho 2013 Desenvolvimento OO com Java 25
class Valor { int i; public Valor(int i) { this.i = i; } } public class Teste { public static void main(String[] args) { Integer m = new Integer(100); System.out.println(m); // 100 Valor v = new Valor(100); System.out.println(v); // Valor@82ba41 } }
O método toString()
Julho 2013 Desenvolvimento OO com Java 26
class Valor { int i; public Valor(int i) { this.i = i; } public String toString() { return "" + i;} } public class Teste { public static void main(String[] args) { Integer m = new Integer(100); System.out.println(m); // 100 Valor v = new Valor(100); System.out.println(v); // 100 } }
Conclusões • Hierarquias polimórficas são mais extensíveis; • O polimorfismo permite a criação de métodos mais gerais, graças à amarração tardia;
• Classes e métodos abstratos auxiliam na criação de hierarquias de classes melhores;
• A classe Object, ancestral de todas as classes Java, promove polimorfismo em grande escala com seus métodos.
Julho 2013 Desenvolvimento OO com Java 27
Interfaces
Julho 2013 Desenvolvimento OO com Java 28
Interfaces • Uma classe abstrata é pura quando:
– Possui métodos abstratos; – Não possui métodos concretos; – Não possui atributos.
• Java oferece a palavra reservada interface: – Cria uma classe abstrata pura; – Chamaremos pelo nome de interface; – Ao conversar com outros programadores, cuidado para não confundir com “interface com o usuário”.
Julho 2013 Desenvolvimento OO com Java 29
CaracterísOcas • Estabelece a interface (o contrato) de um conjunto de classes;
• Permite a construção de código genérico: – Trabalha com qualquer objeto que implemente a interface;
– Obriga programadores a implementar determinados métodos em suas classes para usar seu código.
• Classes uOlizam implements ao invés de extends para implementar uma interface.
Julho 2013 Desenvolvimento OO com Java 30
17/9/15
6
Interfaces
Julho 2013 Desenvolvimento OO com Java 31
interface Forma { void desenhar(); void aumentar(int t); } abstract class Poligono implements Forma { private int lados; public Poligono(int lados) { this.lados = lados; } public int getLados() { return lados; } public abstract void pintar(int cor); }
Interfaces
Julho 2013 Desenvolvimento OO com Java 32
class Linha implements Forma { private int x1, y1, x2, y2; public void desenhar() { /* ... */ } public void aumentar(int t) { /* ... */ } }
Membros da interface • Métodos definidos na interface são automaOcamente públicos;
• Atributos definidos na interface são automaOcamente públicos e estáOcos.
Julho 2013 Desenvolvimento OO com Java 33
interface Forma { int x; void desenhar(); } interface Forma { public static int x; public void desenhar(); }
Definições equivalentes
Membros da interface
Julho 2013 Desenvolvimento OO com Java 34
interface Forma { void desenhar(); void aumentar(int t); } class Linha implements Forma { // Erro: reduziu de público para package-private! void desenhar() { /* ... */ } // Erro: reduziu de público para privado! private void aumentar(int t) { /* ... */ } }
Herança múlOpla • Algumas vezes queremos herdar comportamento de duas classes:
Julho 2013 Desenvolvimento OO com Java 35
Herança múlOpla • Herança múlOpla pode trazer problemas:
– Colisão de nomes; – Herança repeOda.
• Java prima pela simplicidade e não permite herança múlOpla:
Julho 2013 Desenvolvimento OO com Java 36
// Isto não existe em Java! class ProfessorAluno extends Professor, Aluno { }
17/9/15
7
Herança múlOpla com interfaces • Interfaces permitem que simulemos a herança múlOpla:
Julho 2013 Desenvolvimento OO com Java 37
interface VeiculoComPortas { void abrirPortas(); } interface VeiculoComPortaMalas { void abrirPortaMalas(); } interface VeiculoComTetoSolar { void abrirTetoSolar(); }
Herança múlOpla com interfaces
Julho 2013 Desenvolvimento OO com Java 38
class Carrao implements VeiculoComPortas, VeiculoComPortaMalas, VeiculoComTetoSolar { public void abrirPortas() { } public void abrirPortaMalas() { } public void abrirTetoSolar() { } public void andar() { } } public class Teste { static void ap(VeiculoComPortas v) { v.abrirPortas(); } static void apm(VeiculoComPortaMalas v) { v.abrirPortaMalas(); }
Herança múlOpla com interfaces
Julho 2013 Desenvolvimento OO com Java 39
static void ats(VeiculoComTetoSolar v) { v.abrirTetoSolar(); } static void a(Carrao v) { v.andar(); } public static void main(String[] args) { Carrao c = new Carrao(); ap(c); // Upcast: VeiculoComPortas apm(c); // Upcast: VeiculoComPortaMalas ats(c); // Upcast: VeiculoComTetoSolar a(c); // Sem upcast. } }
Interface ou classe abstrata? • Sempre que possível, use interfaces; • Lembre-‐se que Java não suporta herança múlOpla:
– Quando um objeto estende uma classe, não poderá estender nenhuma outra;
– Não “queime” a herança sem necessidade!
Julho 2013 Desenvolvimento OO com Java 41
Colisão de nomes em interfaces • Assim como na herança múlOpla, pode haver colisão de nomes em interfaces: – Não há colisão de implementação (simplifica); – Especificadores de acesso podem colidir; – Tipos de retorno podem colidir.
Julho 2013 Desenvolvimento OO com Java 42
interface Forma { void desenhar(); void inverter(); } class UmaForma implements Forma { protected void desenhar() { } // Erro! public int inverter() { } // Erro! }
Hierarquias de interface • Uma interface pode estender outra:
Julho 2013 Desenvolvimento OO com Java 43
interface Forma { void desenhar(); void aumentar(int t); } interface FormaInversivel extends Forma { void inverter(); } class UmaForma implements Forma { /* ... */ } class OutraForma implements FormaInversivel { /* ... */ }
17/9/15
8
Exemplo de Interface: Comparable
Julho 2013 Desenvolvimento OO com Java 44
A interface Comparable • Um exemplo de interface na API Java é a interface Comparable;
• Define o método compareTo(Object obj): – Compara o objeto atual (this) com o objeto informado (obj);
– Retorna 0 se this = obj; – Retorna um número negaOvo se this < obj; – Retorna um número posiOvo se this > obj.
• Métodos genéricos a uOlizam para ordenar coleções de elementos.
Julho 2013 Desenvolvimento OO com Java 45
A interface Comparable
Julho 2013 Desenvolvimento OO com Java 46
class Livro implements Comparable { double preco; public Livro(int v) { preco = v; } public int compareTo(Object obj) { return preco - ((Livro)obj).preco; } public String toString() { return "" + valor; } }
A interface Comparable
Julho 2013 Desenvolvimento OO com Java 47
public class Teste { static void imprimir(Object[] vetor) { for (int i = 0; i < vetor.length; i++) System.out.print(vetor[i] + "; "); System.out.println(); } public static void main(String[] args) { Valor[] vetor = new Valor[] { new Valor(10), new Valor(3), new Valor(15), new Valor(7) }; imprimir(vetor); // 10; 3; 15; 7; Arrays.sort(vetor); imprimir(vetor); // 3; 7; 10; 15; } }
Exemplo de uso de Interfaces: Coleções
Julho 2013 Desenvolvimento OO com Java 48
Coleções • Grupos de objetos são muito uOlizados em nossos programas;
• Uso de vetores traz uma restrição: tamanho limitado; • Java oferece diversas classes que implementam coleções no pacote java.util;
• As principais: – Listas; – Conjuntos; – Mapeamentos (mapas).
Julho 2013 Desenvolvimento OO com Java 49
17/9/15
9
A API Collec&ons • A API de coleções está presente desde os primórdios, evoluindo a cada versão;
• Vantagens de usá-‐la: – ReuOlizar código já pronto e bastante testado; – Usar código que todos os desenvolvedores usam; – Não se preocupar com o tamanho da coleção.
• Desvantagem: – Sem uso de Opos genéricos (próximo capítulo), não há como restringir a classe do objeto adicionado e é necessário fazer downcast toda vez que quiser ler.
Julho 2013 Desenvolvimento OO com Java 50
A API Collec&ons
Julho 2013 Desenvolvimento OO com Java 51
Julho 2013 Desenvolvimento OO com Java 52 http://ordinarygeek.me/2009/12/02/an-overview-and-comparison-of-java-util-collections/
Listas • Coleções indexadas (ordem é importante):
– ArrayList: usa vetores (desempenho melhor); – LinkedList: usa lista encadeada (úOl para algumas situações).
• Métodos principais: – add(Object), add(int, Object), addAll(Collection);
– clear(), remove(int), removeAll(Collection); – contains(Object), containsAll(Collection); – get(int), indexOf(Object), set(int, Object); – isEmpty(), toArray(), subList(int, int), size().
Julho 2013 Desenvolvimento OO com Java 53
Listas
Julho 2013 Desenvolvimento OO com Java 54
import java.util.*; public class Teste { public static void main(String[] args) { List impares = new ArrayList(); impares.add(1); impares.add(3); impares.add(5); List pares = new LinkedList(); pares.add(2); pares.add(4); pares.add(6); for (int i = 0; i < impares.size(); i++) System.out.println(impares.get(i)); for (int i = 0; i < pares.size(); i++) System.out.println(pares.get(i)); } }
Conjuntos • Coleções não indexadas sem duplicação (não pode haver dois objetos iguais): – HashSet: usa tabela hash (dispersão); – TreeSet: usa árvore e é ordenado (Comparable).
• Métodos principais: – add(Object), addAll(Collection); – clear(), remove(int), removeAll(Collection), retainAll(Collection);
– contains(Object), containsAll(Collection); – isEmpty(), toArray(), size().
Julho 2013 Desenvolvimento OO com Java 55
17/9/15
10
Iteradores • Em conjuntos, não há um método para obter o objeto pelo índice, pois não há índice;
• Para acessar os elementos de conjuntos, usamos iteradores: – ObOdo via método iterator(); – Métodos: hasNext(), next() e remove().
• Funciona também para listas e outras coleções.
Julho 2013 Desenvolvimento OO com Java 56
Conjuntos e iteradores
Julho 2013 Desenvolvimento OO com Java 57
import java.util.*; public class Teste { public static void main(String[] args) { Set numeros = new HashSet(); numeros.add(1); numeros.add(2); numeros.add(3); Set outros = new TreeSet(); outros.add(3); outros.add(2); outros.add(1); Iterator i; for (i = numeros.iterator(); i.hasNext();) System.out.println(i.next()); for (i = outros.iterator(); i.hasNext();) System.out.println(i.next()); } }
Novo loop for (for-‐each) • A parOr do Java 5.0, surgiu uma nova sintaxe para laços que usam iteradores;
• Maior redigibilidade e legibilidade – use sempre que possível!
• Fica ainda melhor com Opos genéricos...
Julho 2013 Desenvolvimento OO com Java 58
for (Object o : numeros) System.out.println(o); for (Object o : outros) System.out.println(o);
Mapeamentos (mapas) • Coleções de pares chave x valor, sem duplicação de chave: – HashMap: usa tabela hash; – TreeMap: usa árvore e é ordenado (Comparable).
• Métodos principais: – clear(), remove(Object); – containsKey(Object), containsValue(Object); – isEmpty(), size(); – put(Object, Object), get(Object), putAll(Map);
– entrySet(), keySet(), values().
Julho 2013 Desenvolvimento OO com Java 59
Mapeamentos (mapas)
Julho 2013 Desenvolvimento OO com Java 60
import java.util.*; public class Teste { public static void main(String[] args) { Map mapa = new HashMap(); mapa.put(1, "Um"); mapa.put(2, "Dois"); mapa.put(3, "Três"); for (Object o : mapa.keySet()) System.out.println(o + " = " + mapa.get(o)); } }
Ordenação de coleções • Java já implementa algoritmo de ordenação:
– Coleções ordenadas: TreeSet, TreeMap; – Collections.sort() para coleções; – Arrays.sort() para vetores.
• Para que a ordenação funcione, é preciso que os objetos implementem a interface Comparable (como vimos na parte 7 do curso);
• As classes Arrays e Collections possuem outros métodos úteis: busca binária, cópia, máximo, mínimo, preenchimento, trocas, etc.
Julho 2013 Desenvolvimento OO com Java 61
17/9/15
11
Comparadores • Quando existe mais de uma forma de ordenar objetos, podemos criar comparadores;
• Implementam java.util.Comparator; • Método compare(Object a, Object b) retorna:
– Número negaOvo, se o primeiro a < b; – Zero, se a == b; – Número posiOvo se a > b.
Julho 2013 Desenvolvimento OO com Java 62
Comparadores
Julho 2013 Desenvolvimento OO com Java 63
public class Pessoa implements Comparable { private String nome; private int idade; public Pessoa(String n, int i) { nome = n; idade = i; } public String toString() { return nome + ", " + idade + " ano(s)"; } public int compareTo(Object o) { return nome.compareTo(((Pessoa)o).nome); } /* Continua... */
Comparadores
Julho 2013 Desenvolvimento OO com Java 64
public static class ComparadorIdade implements Comparator { public int compare(Object o1, Object o2) { return (((Pessoa)o1).idade - ((Pessoa)o2).idade); } } }
Comparadores
Julho 2013 Desenvolvimento OO com Java 65
import java.util.*; public class Teste { public static void main(String[] args) { List pessoas = new ArrayList(); pessoas.add(new Pessoa("Fulano", 20)); pessoas.add(new Pessoa("Beltrano", 18)); pessoas.add(new Pessoa("Cicrano", 23)); Collections.sort(pessoas); for (Object o : pessoas) System.out.println(o); Collections.sort(pessoas, new Pessoa.ComparadorIdade()); for (Object o : pessoas) System.out.println(o); } }