Métodos de Programação II (Mestrado Integrado em Engenharia de Comunicações) 1º Ano, 2º Semestre Tipos Genéricos, a classe ArrayList, Hierarquias de classes e Herança em Java Métodos Programação II 1 Tipos genéricos em Java1.5 • Uma classe pode ser definida à custa de um tipo genérico. Este é definido usando parâmetros de “tipo” (i.e. não primitivos). • Usando este conceito, podemos ter uma infinidade de variantes de uma classe. Exemplo: public class Ponto<T> { // tipo genérico Ponto<T> private T x; private T y; // Métodos public Ponto(T cx, T cy) { this.x = cx; this.y = cy; } public T getX() { return this.x; } public T getY() { return this.y; } public void setX(T cx) { this.x = cx } ... } • Podemos declarar: Ponto<Integer> c = new Ponto<Integer>(); • Ou então: Ponto<Double> d = new Ponto<Double>(); • Usando assim tipos parametrizados… Métodos Programação II 2 Primeiras Colecções – a classe ArrayList<E> Tipo referenciado • O Java1.5. oferece um conjunto de classes (que implementam estruturas de dados tradicionais) para armazenamento de objectos. • Estas, agrupam os objectos em unidades compactas e estruturadas, implementando também as necessárias operações para a correcta manipulação e organização dos dados. • Um exemplo é a classe ArrayList que implementa a estrutura de dados vector de dados (array dinâmico) mas sem restrições de crescimento. • Um ArrayList é uma sequência de elementos (tem uma ordem definida pela adição de novos elementos) Métodos Programação II 3 Construção & métodos de ArrayList<E> • Construção: – ArrayList<Ponto> lista = new ArrayList<Ponto>(); • Operações e seus métodos – Adição de uma novo elemento ao fim da lista: lista.add(new Ponto(1,2)); – Adição numa posição definida: lista.add(3, new Ponto(1,2)); Implica que equals() esteja implementado – Eliminar um elemento: lista.remove(p); em Ponto – Eliminar uma posição: lista.remove(1); – Obter um obj numa posição: Ponto p2 = lista.get(2); – Saber a posição de um obj: int index = lista.indexOf(p2); – Saber tamanho da lista: int len = lista.size(); – Substituir uma posição: lista.set(2, new Ponto(3,4)); – Criar um array cópia do ArrayList: Object a[] = lista.toArray(); Métodos Programação II 4 Exercício: class Banco usando ArrayList class Banco { private ArrayList<Conta> lista; private String nome; private double saldo; Banco(String n) { this.nome = n; this.lista = new ArrayList<Conta>(); this.saldo = 0.0; } public void taxas(double valor) { for(Conta c:this.lista) c.debito(valor); } public double saldo_banco() { double temp = 0.0; for(Conta c:this.lista) temp += c.getSaldo(); return(temp); } } Métodos Programação II 5 Herança • Um grande trunfo da programação orientada aos objectos é a sua capacidade de reutilização de código. • Reutilização por duas vias: – Composição de classes: Definir uma nova classe usando objectos de classes já pré definidas – Hierarquia de classes: Definir uma nova classe que é uma especialização da uma classe pré definida: Assim, todo o código da classe geral é herdade pela nova classe. – Temos assim, não um plano de classes mas uma hierarquia Métodos Programação II 6 Herança: Exemplo • Temos a classe Ponto (2 dimensões) que passamos a chamar Ponto2D. • Queremos agora definir uma nova classe para trabalhar no espaço tridimensional (Ponto3D) • Esta nova classe de reutilizar todo o código de Ponto2D adicionando nova informação (neste caso uma terceira dimensão). Em Java define-se: Keyword para definir subclasse class Ponto3D extends Ponto2D { private double z; Ponto3D(double x, double y, double z) { super(x,y); this.z = z;} Referência à super classe Public double getZ() // método local a Ponto3D { return this.z; } } Métodos Programação II 7 Herança em Java • Definição de uma subclasse implica a definição de um subtipo! • Herança simples (uma classe tem um só “progenitor”) • Herdar e ter “acesso” não é necessariamente a mesma coisa (pelas questões de visibilidade) • Três pontos a resolver: – Redefinição (reescrita) de métodos e variáveis – Procura de métodos (lookup de métodos dinâmico) – Criação das instâncias das subclasses. • Há sempre forma de parar a hierarquia, pela keyword final. Uma classe definida usando “final class” não pode ter subclasses. Uma variável ou método final não pode ser reescrito. Métodos Programação II 8 Redefinição de métodos • Um método na subclasse reescreve o método herdado se tiver a mesma assinatura. • Exemplo do método toString() em Ponto3D. class Ponto3D extends Ponto2D { …. public String toString() { return super.toString() + “,” + this.z; } } • Criação de instâncias: – – – – Ponto2D p1 = new Ponto2D(1,2); Ponto2D p2 = new Ponto3D(1,2,3); Ponto3D p3 = new Ponto3D(3,2,1); String t = p2.toString(); Métodos Programação II Dynamic Binding: compilador atribui o tipo à variável; o interpretador pode ter de decidir o tipo de uma variável. 9 Redefinição de variáveis public class A { int i = 0; int m() { return this.i; } } public class B extends A { int this.i = 1; // i de A é “shadowed” int m() { return this.i; } // m é “overriden” } …. A a = new A(); A b = new B(); b.m() // dá como resultado 1 e não 0 !! Por exemplo, um método de B poderia ter o seguinte código: public int mb() { this.i = super.i + 10; return this.i + this.m() + super.m(); } i -> local super.i -> i da superclasse this.m() -> local super.m() -> m() da superclasse Métodos Programação II 10 Redefinição: Exemplo public static void main(String args[]) { public class C extends A public class A A a1, a2, a3, a4; { a3 = new C(); a4 = new D(); { private int a; a1 = new A(); a2 = new B(); private a4.metd(); int c; a1.metd(); public A() { this.a = 1; } a2.metd(); a3.metd(); C() { this.c = 3; } out.println("a1.metd() = " +public a1.daVal()); public int daVal() { return this.a; } int daVal() { return this.c; } out.println("a2.metd() = " +public a2.daVal()); public void metd() { this.a += 10; } void metd() { this.c += 30 ; } out.println("a3.metd() = " +public a3.daVal()); } out.println("a4.metd() = "}+ a4.daVal()); public class B extends A public class D extends C } { { private int b; private int d; public B() { this.b = 2; } public D() { this.d = 33; } public int daVal() { return this.b; } public int daVal() { return this.d; } public void metd() { this.b += 20 ; } public void metd() { this.d = this.d * 10 + 3 ; } } } Métodos Programação II 11 Exemplo EMPREGADO GESTOR MOTORISTA Métodos Programação II 12 Exemplo public class Empregado { // Variáveis de Classe public static double salDia = 50.00; public static double getSalDia() { return salDia; } // Variáveis de Instância private String nome; private int dias; // dias de trabalho no mês // Construtores public Empregado(String nome, int dias) { this.dias = dias; this.nome = nome; } // Métodos de Instância public int getDias() { return dias; } public double salario() { return dias * getSalDia(); } public String getNome() { return nome; } } public class Motorista extends Empregado { // Variáveis de Classe public static double valorKm = 0.98; public class Gestor extends Empregado public static double mudaValKm(double nvKm) { // Variáveis de Instância e Construtores { valorKm = nvKm; } // Variáveis de Instância e Construtores private double bonus; private double bonus; public Gestor(String nm, int dias, double bon) private int km; { super(nm, dias); bonus = bon; } public Motorista(String nm, int dias, double bon, int km) // Métodos de Instância {super(nm, dias); bonus = bon; this.km = km; } public double getBonus() { return bonus; } // Métodos de Instância public double salario() public double getBonus() { return bonus; } { return getSalDia()*this.getDias()*bonus; } public double salario() { return getSalDia()*this.getDias()*bonus + (valorKm*km); } } Métodos Programação II 13 } Interpretação de this em hierarquias de classes Invocar a.teste() (sendo a uma instância de SubA) : A interpretação de this refere-se sempre ao objecto para onde a mensagem é enviada. Neste caso, como teste() é um método herdado, ele é invocado em Super. No entanto como teste() refere a this.getX(), a procura do método faz-se na subclass SubA. Aqui acontece simplesmente o return x, sendo x a variável de SubA. Assim o resultado desta mensagem é x = 20. Em geral, a expressão this.m() onde quer que seja encontrada no código de um método de instância de uma dada classe da hierarquia, corresponderá sempre à execução do método m() da classe do receptor da mensagem que despoletou o algoritmo de procura Métodos Programação II 14 Hierarquia em Java: classe Object • A classe Object representa o topo da hierarquia de classes em Java. • Uma variável do tipo Object pode fazer referência para qualquer tipo referenciado. • Especificam os métodos clone(), equals() e toString(). • Contém o método getClass() que retorna a classe a que um objecto pertence. • Com getClass().getName() obtemos o nome da classe. Métodos Programação II 15 Notas finais sobre Herança • Só podemos user a keyword super uma vez numa expressão e.g. a expressão super.super.m() é inválida. • Variáveis e métodos de classe não são herdadas mas as variáveis podem ser redefinidas. Aos métodos static acontece o inlining (o compilador substitui invocação por código efectivo) em cada subclasse. • Pelo facto de uma variável de um dado tipo estático poder possuir diferentes tipos dinâmicos (ou formas) em tempo de execução, ela diz-se polimórfica. • Polimorfismos das variáveis = princípio da substituição. • Algoritmo de procura dinâmica de métodos e associação dinâmica! Permite ao interpretador decidir (em situações de herança) qual o método a executar. Métodos Programação II 16 Exercícios • Definir uma classe Forma. • Definir a seguinte hierarquia de classes: • Implementar os métodos apresentados. • Definir a classe FigGeo que guarda um conjunto de figuras geométricas. • Adicionar a classe Quadrado e Elipse (subclasse de Círculo) • Implementar um método que determina a figura com a maior área e qual o seu tipo e outro método para o maior perímetro. • Um método para contabilizar o número de figuras por tipo. Métodos Programação II 17 Exercícios • Criar um banco que guarda as contas num ArrayList • Definir vários novos tipos de conta: conta a prazo, conta jovem, conta ordenado e conta Capital. – Prazo, tem uma taxa e um número de dias – Jovem, tem taxa fixa de 1% ao ano – Ordenado, dá um plafond de um valor pré definido. Isto é, permite estar com saldo devedor até ao montante estabelecido. – Conta Capital, que contém uma taxa de juro variável, indexada por períodos. A rentabilidade é calculada sobre estes períodos. • Calcular os juros que o banco tem de pagar aos seus clientes. • Calcular o nº de contas por tipo bem como o saldo total depositado no banco referente a contas Capital. Métodos Programação II 18