Baixe o app para aproveitar ainda mais
Prévia do material em texto
1 FACULDADE DE COMPUTAÇÃO E INFORMÁTICA BACHARELADOS EM CIÊNCIA DA COMPUTAÇÃO E SISTEMAS DE INFORMAÇÃO E TECNOLOGIA EM ANÁLISE E DESENVOLVIMENTO DE SISTEMAS Linguagem de Programação I – SEMANA 07 TEORIA: COLEÇÕES DE OBJETOS COM ARRAYLIST Nossos objetivos nesta aula são: Introduzir o polimorfismo paramétrico; Mapear coleções de objetos via Java Collections com ArrayList; Aprender a comparar objetos. A referência para esta aula é: Capítulo 5 – Seção 5.2.4 (Comparando Objetos) e Capítulo 7 (Arrays e Listas de Arrays) do nosso livro-texto: Horstmann, C. Conceitos de Computação com Java. 5.ed. Porto Alegre: Bookman, 2009. Não deixem de ler estes capítulos antes e após a aula! COLEÇÕES DE OBJETOS COM ARRAYLIST Na implementação do relacionamento 1: N da aula anterior, utilizamos um vetor de objetos BankAccount. Este vetor simples em Java pode ser chamado de uma coleção de objetos. public class Bank { private BankAccount accounts[]; // contas bancárias private int last; // último índice do banco inserido public Bank(){ accounts=new BankAccount[100]; // banco com, no máximo, 100 contas bancárias last=0; } . . . } 2 A Linguagem Java disponibiliza diversas estruturas para representar coleções de objetos, chamadas Java Collections. Uma delas, em particular, pode facilitar a implementação de vários dos nossos métodos anteriores: classe ArrayList. A classe ArrayList é uma estrutura linear indexada, implementada como um vetor dinâmico. Isto quer dizer que podemos acessar elementos de um ArrayList por um índice e que não precisaremos nos importar com limites do vetor: sempre que houver um estouro de índice e houver memória, o vetor será realocado com uma nova capacidade. Vamos, agora, refatorar a nossa classe Bank para utilizar um ArrayList no lugar de um vetor tradicional. O primeiro passo será alterar os atributos e o construtor: import java.util.ArrayList; public class Bank { private ArrayList<BankAccount> accounts; public Bank(){ accounts = new ArrayList<BankAccount>(); } … } Na nova declaração do atributo accounts, utilizamos ArrayList<BankAccount>. Este tipo de declaração diz que cada elemento de ArrayList será do tipo BankAccount. Estudaremos este mecanismo posteriormente e o chamaremos de polimorfismo paramétrico. Dizemos que a classe ArrayList é polimórfica e que a estamos parametrizando com o tipo BankAccount. Em seguida, vamos implementar o método addAcount: private ArrayList<BankAccount> accounts; public void addAccount(BankAccount a){ // Insere conta na classe Bank accounts.add(a); // insere elemento no final do ArrayList } 3 Agora, a parte mais interessante ocorre na implementação do método find. Ele pode ser implementado da maneira tradicional como: private ArrayList<BankAccount> accounts; public BankAccount find(int accountNumber){ for (int i=0;i<accounts.size();i++){ BankAccount elem=(BankAccount) accounts.get(i); // conta bancária de índice i if (elem.getAccountNumber()==accountNumber) return elem; } return null; } Porém, quando trabalhamos com coleções, podemos utilizar uma construção chamada foreach ou for avançado que torna no nosso código mais limpo: private ArrayList<BankAccount> accounts; public BankAccount find(int accountNumber){ for (BankAccount b : accounts) // para cada conta bancária em accounts if (b.getAccountNumber()==accountNumber) return b; return null; } Dizemos, no código acima, que b é um iterador sobre a coleção accounts. O nome iterador vem do fato que b realiza um processo de iteração (percurso) sobre os elementos da coleção. Observe que, neste tipo de for, não nos interessa o índice do elemento, mas o elemento em si. 4 EXERCÍCIO COM DISCUSSÃO EM DUPLAS Refatore os métodos restantes da classe Bank para utilizar o ArrayList. Sempre que possível, utilize iteradores para percorrer o ArrayList. public class Bank { … public double getTotalBalance(){... } public BankAccount getMaximum(){. ..} public int count(int limit){… } } 5 COMPARAÇÃO DE OBJETOS Queremos, agora, introduzir um método na classe Bank para que, dada uma instância de BankAccount, saber se esta classe está ou não na coleção de contas. Assim, uma primeira tentativa para implementar este método poderia ser: private ArrayList<BankAccount> accounts; public boolean contains(BankAccount a){ for (BankAccount b : accounts) // para cada conta bancária em accounts if (b == a) return true; return false; } Infelizmente, o teste de igualdade == pode não funcionar para objetos, pois estamos testando se as referências são iguais e não os conteúdos dos objetos. Para comparar se dois objetos têm o mesmo conteúdo, usamos o método equals, conforme mostrado abaixo: private ArrayList<BankAccount> accounts; public boolean contains(BankAccount a){ for (BankAccount b : accounts) // para cada conta bancária em accounts if (b.equals(a)) return true; return false; } Várias classes em Java já possuem o método equals implementado. Nós, teremos que implementar o método na classe BankAccount: 6 class BankAccount{ private int accountNumber; // número da conta private String password; // senha da conta private String owner; // proprietário da conta private double balance; // saldo da conta ... public boolean equals(Object obj) { BankAccount b = (BankAccount) obj; return accountNumber == b.getAccountNumber() && password.equals(b.getPassword()) && owner.equals(b.getOwner()) && balance == b.getBalance(); } } Observem que, quando comparamos tipos primitivos (int, double,...) utilizamos a comparação == e, quando testamos igual de objetos (como os testes para String), utilizamos equals. EXERCÍCIO COM DISCUSSÃO EM DUPLAS Implemente, na classe Bank, dois métodos para remover contas bancárias: o Um, que recebe somente o número da conta o Outro, que recebe a instância da conta a ser removida public class Bank { … public void removeAccount(int accountNumber){ // Remove uma conta pelo seu número } 7 public void removeAccount(BankAccount b){ // Remove uma conta dada uma instância } } Lembrando que é possível termos métodos com o mesmo nome dentro de uma classe, porém com parâmetros diferentes. Isto chama-se polimorfismo por sobrecarga (overloading) e dizemos que o método removeAccount é polimórfico. 8 ATIVIDADE DE LABORATÓRIO – Etapa 02 Nossa atividade de laboratórioirá estender várias funcionalidades da classe Bank, implementada na aula teórica. Vamos supor que a etapa 01 já foi realizada com a leitura das informações nas nossas contas bancárias de um arquivo. Ou seja, já implementamos um construtor na classe Bank que recebeu como entrada o nome de um arquivo contendo informações das contas e preencheu o vetor de contas do banco. O formato do arquivo de entrada ficou da seguinte forma: Número de contas Número da Conta 1#Senha da Conta 1#Proprietário da Conta 1#saldo da Conta1 Número da Conta 2#Senha da Conta 2#Proprietário da Conta 2#saldo da Conta2 ... Número da Conta N#Senha da Conta N#Proprietário da Conta N#saldo da ContaN Observe que os campos de cada conta estão separados por #. Sugestão: utilize o método split(...) da classe String para separar os campos. class Bank { ... public Bank(String filename){ // Inicializa as contas bancárias com base em um arquivo } } 1. Implemente, na classe Bank, um método chamado sort(), que ordena todas as contas do banco pelos seus números, utilizando o método da seleção. 2. Implemente, na classe Bank, um método privado chamado dump(...), que receba o nome de um arquivo e grave todas as informações do banco neste arquivo, seguindo o formato de entrada. Conta número: <numero da conta> Senha: <senha da conta> Proprietário: <nome do proprietário> Saldo: <saldo da conta> 3. Refatore, na classe Bank, o método de busca linear do método find(...) para o método de busca binária. 4. Implemente uma classe principal para visualizar e testar se os métodos implementados estão corretos. 5. Faça testes unitários para cada um dos construtores e métodos implementados. 9 EXERCÍCIOS EXTRA-CLASSE 1. Implemente, na classe Bank, um método changeAccount(...) para substituir os dados de uma conta atual (oldAccount), caso exista, pelos dados de uma nova conta (newAccount): public void changeAccount (BankAccount oldAccount, BankAccount newAccount){...} 2. Implemente, na classe Bank, um método getAccounts() para obter a coleção de contas bancárias. public ArrayList<BankAccount> getAccounts(){...} 3. Implemente, na classe Bank, um método importAccounts(...), que recebe uma instância da classe Bank e importa todas as contas desta instância. Casa haja conflito de números de conta, as duas contas com números iguais deverão ser mantidas. public void importAccounts(Bank b){...} 4. Implemente, na classe Bank, uma versão polimórfica do método sort() para, ao invés de ordenar a própria coleção de contas, devolver uma cópia ordenada deste coleção, mantendo a coleção inicial na sua forma original: public void sort(ArrayList<BankAccount> ord){…} 5. Implemente, na classe Bank, um método commonOwners(...) que recebe uma instância de um outro banco e devolve uma coleção de nomes comuns de proprietários de contas: public ArrayList<String> commonOwners(Bank b){...}
Compartilhar