Coleções Podemos definir coleção como a representação de um grupo de objetos, semelhante aos arrays. No entanto, as coleções são implementações que geralmente encapsulam arrays, oferecendo algumas facilidades como: ● ● ● ● ● busca; inserção; redimensionamento dinâmico; remoção de elementos; ordenação Exemplos da utilização de coleções Quando fazemos consultas em banco de dados e queremos armazenar os objetos que representam o resultado da consulta em um único objeto. Exemplo: A consulta de clientes por categoria pode retornar uma coleção de objetos cliente. Mapeamento de relações 1 para muitos, ou seja, um cliente tem muitos endereços. Podemos dizer que um objeto do tipo Cliente tem uma coleção de objetos do tipo Endereco. Vantagens na utilização de coleções Não é necessário implementar busca, redimensionamento e etc. métodos de ordenação, Normalmente, há a melhora na performance, pois provê implementações otimizadas criadas por especialistas. Interface em Java O que é uma interface? ● A interface é uma forma de especificação de comportamento de classes, onde definimos todos os métodos que devem ser implementados pela classe, garantindo que as classes que implementem a interface terão, obrigatoriamente, todos os métodos definidos na interface; ● Interfaces definem a forma como iremos interagir com as classes que a implementam; 1 ● Interface é um protótipo de classe; A Interface Collection (java.util.Collection) A interface Collection é a especificação representa um grupo de objetos chamados de elementos. que Existem diferentes implementações e sub-interfaces da interface Collection que oferecem vantagens e desvantagens, dependendo da situação, podemos encontrar coleções com as seguintes características: ● ● ● Algumas permitem elementos duplicados e outras não Algumas são ordenadas e outras não Algumas permitem a inserção do elemento null e outras não Esta interface é utilizada apenas como "objeto para polimorfismo" para que um método possa receber uma Collection genérica, ou seja, qualquer classe que a implemente ou uma de suas sub-interfaces. <<Interface>> Collection <<Interface>> Set <<Interface>> List Importância da Sobrescrita do hashCode e equals equals() O que acontece quando comparamos dois objetos da mesma classe utilizando o operador == ? Inicialmente, poderíamos acreditar que os atributos que compõe cada um dos objetos seriam comparados, retornando true se todos forem idênticos. Porém, a JVM verifica se a referência dos objetos é a mesma, ou seja, se os endereços de memória são iguais. 2 De acordo com a documentação do JavaDoc da classe Object, que define o método equals(), devemos sempre sobrescreve-lo levando em consideração as seguintes relações: Reflexão: x.equals(x) deve ser true para qualquer x diferente de null; Simetria: Para x e y diferentes de null, se x.equals(y) é true, então y.equals(x) também deve ser; Transitividade: Para x, y e z diferentes de null, se x.equals(y) é true, e y.equals(z) é true, então x.equals(z) também deve ser true; Consistência: Para x e y diferentes de null, múltiplas chamadas de x.equals(y) devem sempre retornar o mesmo valor; Para x diferente de null, x.equals(null) deve sempre retornar false Vamos analisar alguns exemplo para entender o uso do método equals(). Pessoa.java public class Pessoa{ private String nome; private String RG; public Pessoa(String nome, String RG){ this.setNome(nome); this.setRG(RG); } public void setNome(String nome){ this.nome = nome; } public void setRG(String RG){ this.RG = RG; } public String getNome(){ return nome; } public String getRG(){ return RG; } } 3 TestePessoa.java public class TestePessoa{ public static void main (String args[]){ Pessoa p1 = new Pessoa("Jessica", "752"); Pessoa p2 = new Pessoa("Jessica", "752"); if (p1 == p2){ System.out.println("p1 igual p2 com =="); } else{ System.out.println("p1 != p2 com =="); } } } Veja abaixo a saída gerada pela execução da classe TestePessoa.java. p1 != p2 com == Os objetos foram considerados diferentes pelo operador ==, embora contenham atributos idênticos, pois a referência aos objetos na memória heap é diferente. Vamos analisar um novo exemplo, porém desta utilizando o método equals() herdado da classe Object. vez TestePessoa.java public class TestePessoa{ public static void main (String args[]){ Pessoa p1 = new Pessoa("Jessica", "752"); Pessoa p2 = new Pessoa("Jessica", "752"); if (p1.equals(p2)){ System.out.println("p1 igual p2 com equals da classe Object"); } else{ System.out.println("p1 != p2 com equals da classe Object"); } } } Veja abaixo a saída gerada pela execução da classe TestePessoa.java, agora com a utilização do método equals da classe Object. p1 != p2 com equals da classe Object A comparação utilizando o método equals apresentou o mesmo resultado daquele que utilizou o operador ==. Isto 4 aconteceu porque o método equals, herdado da classe Object, emprega o operador == para comparar objetos. Se o objetivo é informar que os objetos da classe Pessoa são iguais caso o conteúdo de todos os seus atributos forem iguais, devemos então sobrescrever o método equals na classe Pessoa. Veja abaixo as alterações TestePessoa.java. nas classes Pessoa.java e Pessoa.java public class Pessoa{ private String nome; private String RG; public Pessoa(String nome, String RG){ this.setNome(nome); this.setRG(RG); } public void setNome(String nome){ this.nome = nome; } public void setRG(String RG){ this.RG = RG; } public String getNome(){ return nome; } public String getRG(){ return RG; } //Sobrescrita do método equals da classe Object public boolean equals(Object o){ //Devemos verificar se o objeto "o" eh uma //instancia da classe Pessoa if (o instanceof Pessoa){ //Devemos fazer o cast de Object para Pessoa Pessoa p = (Pessoa) o; if (this.getNome().equals(p.getNome()) && this.getRG().equals(p.getRG())){ return true; } else{ return false; } } else{ return false; } } } 5 TestePessoa.java public class TestePessoa{ public static void main (String args[]){ Pessoa p1 = new Pessoa("Jessica", "752"); Pessoa p2 = new Pessoa("Jessica", "752"); if (p1.equals(p2)){ System.out.println("p1 igual p2 com equals da classe Pessoa"); } else{ System.out.println("p1 != p2 com equals da classe Pessoa"); } } } Veja abaixo a saída gerada pela execução da classe TestePessoa.java, agora com a utilização do método equals da classe Pessoa. p1 igual p2 com equals da classe Pessoa hashCode() Segundo o JavaDoc da classe Object, o método hashCode() retorna números inteiros distintos para objetos distintos. Este número é gerado pela conversão do endereço interno do objeto em um número inteiro. As implementações de equals e hashCode devem ser coerentes, ou seja, sempre que dois objetos forem considerados iguais pelo método equals, os dois objetos também devem possuir o mesmo hashCode. Embora não seja exigido pela especificação que dois objetos diferentes tenham hashCodes diferentes, é coerente implementar os métodos de forma que objetos diferentes tenham hashCodes diferentes. A implementação de hashCode, pode ser baseada implementação de hashCode dos atributos da classe. na Vamos criar uma classe Funcionário que tem atributos: nome e fone. Ambos do tipo String; O método equals da classe Funcionário irá retornar true se e somente se o nome e o fone do Funcionário forem iguais; O hashCode do Funcionário será calculado somando o hashCode do nome e do fone do Funcionário. dois 6 Veja o exemplo abaixo que sobrescreve equals() e hashCode() da classe Object Funcionário. os métodos na classe Funcionario.java public class Funcionario{ String nome; String fone; public boolean equals(Object o){ //Devemos verificar se o objeto "o" eh uma //instancia da classe Funcionario if (o instanceof Funcionario){ //Devemos fazer o cast de Object para Funcionario Funcionario f = (Funcionario) o; if (this.nome.equals(f.nome) && this.fone.equals(f.fone)){ return true; } else return false; } else return false; } public int hashCode(){ return this.fone.hashCode() + this.nome.hashCode(); } public static void main (String args[]){ Funcionario f1 = new Funcionario(); Funcionario f2 = new Funcionario(); f1.nome = "Joao"; f1.fone = "564"; f2.nome = "Joao"; f2.fone = "564"; if (f1.equals(f2)){ System.out.println("f1 igual f2"); System.out.println("hashCode f1: " + f1.hashCode()); System.out.println("hashCode f2: " + f2.hashCode()); } else{ System.out.println("f1 diferente f2"); System.out.println("hashCode f1: " + f1.hashCode()); System.out.println("hashCode f2: " + f2.hashCode()); } } } 7 Conjuntos (Set), Listas (List) e Mapeamento (Map) A Interface List (java.util.List) A interface List define uma coleção ordenada, também conhecida como seqüência. Por isto, quando utilizamos objetos que implementem esta interface, obtemos o controle sobre a posição em que os elementos são inseridos, sendo possível acessá-los através de um índice inteiro (posição na lista). Exemplo: Índice List 0 obj1 1 obj2 2 obj3 ... ... n Objn Normalmente as classes que implementam esta interface permitem elementos duplicados e elementos null. Hierarquia <<Interface>> Collection <<Interface>> List ArrayList 8 A Interface Set (java.util.Set) Esta Collection é a representação de matemáticos, e caracteriza-se por não possuir repetidos no seu interior. conjuntos elementos De que maneira é feita a análise de elementos idênticos? Tecnicamente, a Set verifica um a um os objetos existentes em seu interior com o elemento a ser incluído. Esta verificação é feita invocando o método equals de cada um dos objetos, passando como parâmetro o objeto a ser inserido. Se a análise retornar true o objeto não será incluído ao Set. <<Interface>> Collection <<Interface>> Set HashSet A Interface Map (java.util.Map) Esta interface define objetos que mapeiam chaves e valores, onde as chaves não podem ser duplicadas, mas os valores sim. Map chave (Object) Valor (Object) Pessoa1 Filho1 Pessoa2 Filho2 Pessoa3 Filho3 ... ... PessoaN FilhoN Não aceita elementos repetidos Aceita elementos repetidos 9 Desta forma, não há nenhuma restrição específica ao valor null, exceto pelo fato que a condição de chaves não repetidas seja respeitada, ou seja, é possível adicionar apenas uma chave igual a null e quantos valores null forem necessários. A interface oferece três visualizações distintas de um Map: As chaves podem ser visualizadas como um objeto do tipo Set; Os valores podem ser vistos como uma coleção de objetos; Conjunto (objeto do tipo Set) de pares chaves-valor. Usando Estruturas de Listas ArrayList A classe ArrayList (java.util.ArrayList) É uma implementação da interface List, onde o tamanho do array pode ser alterado em tempo de execução. Quando utilizamos ArrayList é permitida a inserção de todo tipo de elementos, inclusive null. Construtores ● ArrayList(): Constrói um ArrayList capacidade inicial de 10 posições; vazio, ● ArrayList(int capacidadeInicial): Constrói ArrayList vazio com a capacidade inicial igual parâmetro informado; com um ao Métodos para adicionar elementos ao ArrayList ● void add(int i, Object obj): Adiciona o novo objeto obj na posição i; ● boolean add(Object obj): Adiciona o novo objeto obj na última posição do ArrayList; ● Object set(int i, Object obj): Substitui um objeto existente no ArrayList na posição i pelo objeto obj; É importante observar que os métodos acima recebem como parâmetro um Object e, por isto, sempre que é passado um objeto específico, como por exemplo, um Cliente ou uma String é realizado um upcast automático. 10 Método para verificar se o ArrayList contém um determinado elemento: ● boolean contains(Object obj): Retorna true se o ArrayList possui o objeto obj. A análise é baseada no método equals implementado na classe obj. Métodos para recuperar elementos ou posição de um elemento dentro do ArrayList: ● Object get(int pos): Retorna o elemento que está na posição pos do ArrayList; ● int indexOf(Object obj): Retorna a posição do objeto obj no ArrayList. Caso o Object obj não seja encontrado, o método irá retornar -1; Método para remover elementos do ArrayList: ● Object remove(int index): estiver na posição index. Remove o elemento que Método para verificar o tamanho / número de elementos do ArrayList: ● int size(): ArrayList; Retorna o número de elementos do Abaixo temos um exemplo da utilização da classe ArrayList. public class Funcionario { private String nome; private int idade; public Funcionario(String nome, int idade){ this.setNome(nome); this.setIdade(idade); } public int getIdade() { return idade; } public void setIdade(int idade) { this.idade = idade; } public String getNome() { return nome; } 11 public void setNome(String nome) { this.nome = nome; } public String toString(){ String str = "Funcionario: " + nome + "\nIdade: " + idade + "\n"; return str; } } import java.util.ArrayList; public class TesteArrayList { public static void main(String[] args) { //Cria objetos da classe Funcionario Funcionario func1 = new Funcionario("Joao", 35); Funcionario func2 = new Funcionario("Gerson", 42); Funcionario func3 = new Funcionario("Renato", 27); //Adiciona os funcionarios no ArrayList ArrayList funcionarios = new ArrayList(); funcionarios.add(func1); funcionarios.add(func2); funcionarios.add(func3); imprimeFuncionarios(funcionarios); System.out.println("O funcionario 1 serah removido..."); Funcionario funcRemovido = (Funcionario) funcionarios.remove(1); System.out.println("Funcionario removido: " + funcRemovido); imprimeFuncionarios(funcionarios); } private static void imprimeFuncionarios(ArrayList funcionarios){ Funcionario func; System.out.println("Qtde de funcionarios: " + funcionarios.size()); for (int nCont = 0; nCont < funcionarios.size(); nCont++){ func = (Funcionario) funcionarios.get(nCont); System.out.println(nCont + ": \n" + func); } System.out.println("-----------FIM---------------"); } } 12 Veja a saída gerada pela execução da classe TesteArrayList: Qtde de funcionarios: 3 0: Funcionario: Joao Idade: 35 1: Funcionario: Gerson Idade: 42 2: Funcionario: Renato Idade: 27 -----------FIM--------------O funcionario 1 serah removido... Funcionario removido: Funcionario: Gerson Idade: 42 Qtde de funcionarios: 2 0: Funcionario: Joao Idade: 35 1: Funcionario: Renato Idade: 27 -----------FIM--------------- A Interface Iterator (java.util.Iterator) A interface Iterator é utilizada para navegar dentro de coleções como a Set e List. As interfaces Set e List definem o método iterator() que retorna um Iterator. A interface Iterator, por sua vez, possui o método hasNext() para identificar se existem mais elementos na coleção. Outro método importante desta classe é aquele utilizado para obter o próximo elemento da coleção e que possui a seguinte assinatura: Object next() 13 Veja o exemplo abaixo: import java.util.ArrayList; import java.util.Iterator; public class TesteIterator { public static void main(String[] args) { String nome1 = "Carlos"; String nome2 = "Josias"; String nome3 = "Marcos"; String nome4 = "Armando"; ArrayList nomes = new ArrayList(); nomes.add(nome1); nomes.add(nome2); nomes.add(nome3); nomes.add(nome4); Iterator iterator = nomes.iterator(); int iCont = 1; String nome; while (iterator.hasNext()){ nome = (String) iterator.next(); System.out.println("nome[" + iCont++ + "] = " + nome); } } } Saída gerada pela execução do programa acima: nome[1] nome[2] nome[3] nome[4] = = = = Carlos Josias Marcos Armando OBS: Observe que a ordem de inserção dos elementos no ArrayList foi respeitada durante a impressão na tela. Usando Estruturas de Conjunto HashSet A classe HashSet (java.util.HashSet) A classe HashSet é uma das implementações da interface Set, que não é indexada, nem ordenada por natureza. Esta implementação de Set é ideal para buscas, mas não para navegação seqüencial. 14 Construtores ● HashSet(): Constrói um HashSet vazio, com capacidade inicial de 16 posições; HashSet(int capacidadeInicial): Constrói um HashSet vazio com a capacidade inicial igual ao parâmetro informado; Métodos para adicionar elementos ao HashSet ● ● void add(Object obj): adiciona o Object obj se o mesmo já não estiver presente. Este método retorna true se o elemento for inserido; Método para verificar se o HashSet contém um determinado elemento: ● boolean contains(Object obj): HashSet possui o objeto obj. Retorna true se o Ao contrário do ArrayList que possui métodos como get() e indexOf() para recuperar elementos ou posição de elementos, o HashSet não possui estes métodos. Método para remover elementos do HashSet: ● Object remove(Object obj): mesmo estiver presente. Remove o elemento se o Método para verificar o tamanho / número de elementos do HashSet: ● int size(): Retorna o número de elementos do HashSet; Como a coleção Set não é indexada, devemos utilizar a interface Iterator para navegar dentro desta coleção. 15 Veja o exemplo abaixo: import java.util.HashSet; import java.util.Iterator; public class TesteHashSet { public static void main(String[] args) { String nome1 = "Carlos"; String nome2 = "Josias"; String nome3 = "Marcos"; String nome4 = "Armando"; HashSet nomes = new HashSet(); nomes.add(nome1); nomes.add(nome2); nomes.add(nome3); nomes.add(nome4); Iterator iterator = nomes.iterator(); int iCont = 1; String nome; while (iterator.hasNext()){ nome = (String) iterator.next(); System.out.println("nome[" + iCont++ + "] = " + nome); } } } Saída gerada pela execução do programa acima: nome[1] nome[2] nome[3] nome[4] = = = = Armando Marcos Josias Carlos OBS: Observe que a ordem de inserção dos elementos no HashSet não foi respeitada durante a impressão na tela. Usando Estruturas de Mapeamento HashMap A classe HashMap (java.util.HashMap) HashMap é uma implementação da interface Map. Esta implementação não garante a ordem dos seus elementos, nem que estarão sempre na mesma ordem. A classe HashMap permite a inserção de null, mas vale lembrar que a chave deve ser única, isto é, apenas uma poderá ser igual a null. 16 Construtores HashMap(): Constrói um HahsMap vazio com capacidade inicial de 16 posições; ● HashMap(int capacidadeInicial): Constrói um HashMap vazio com a capacidade inicial igual ao parâmetro informado; Método para adicionar um par chave-valor no HashMap Object put (Object chave, Object valor): Adiciona o par chave-valor ao HashMap. Caso tente adicionar um par chave-valor cuja chave já tenha sido adicionada anteriormente, o valor anterior será substituído pelo novo e o método put irá retornar o valor antigo. Caso o par chave-valor não tenha sido adicionado anteriormente, o método put irá retornar null. Métodos para verificar chave ou valor se o HashMap contém determinada boolean containsKey(Object chv): Retorna true se for encontrada a chave chv; boolean containsValue(Object vle): Retorna true se for encontrado o valor vle. Método para recuperar um valor do HashMap Object get(Object chv): Retorna o valor associado à chave chv passada como parâmetro. OBS: Caso a chave não seja encontrada, null será retornado. No entanto, existe a possibilidade de haver uma chave associada ao valor null, portanto é muito importante verificar se a chave existe no HashMap, através do método containsKey(). Método para remover elementos do HashMap Object remove(Object chv): Remove o par chave-valor encontrado no HashMap. 17 Método para verificar o tamanho / número de elementos do HashMap int size(): Retorna o número de pares chave-valor encontrados no HashMap. O exemplo abaixo utiliza um hashMap. Pessoa.java public class Pessoa { private String nome; private String cpf; public Pessoa (String nome, String cpf){ this.nome = nome; this.cpf = cpf; } public String getCpf() { return cpf; } public void setCpf(String cpf) { this.cpf = cpf; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String toString(){ String str = "Nome: " + getNome(); str += "\nCPF: " + getCpf(); return str; } public boolean equals(Object o){ if (o instanceof Pessoa){ Pessoa p = (Pessoa) o; //Verifica se o CPF das pessoas são iguais if (this.getCpf().equals(p.getCpf())) return true; else return false; } else return false; } } 18 TesteHashMap.java import java.util.*; public class TesteHashMap { public static void main (String args[]){ String cpf1 = "251"; Pessoa p1 = new Pessoa ("Carlos", cpf1); String cpf2 = "573"; Pessoa p2 = new Pessoa ("Roberto", cpf2); String cpf3 = "952"; Pessoa p3 = new Pessoa ("Matheus", cpf3); HashMap pessoas = pessoas.put(cpf1, pessoas.put(cpf2, pessoas.put(cpf3, new HashMap(); p1); p2); p3); imprimirMapPessoas(pessoas); String chave = "952"; removerElemento(pessoas, chave); imprimirMapPessoas(pessoas); } public static void imprimirMapPessoas(HashMap pessoas){ Set chaves = pessoas.keySet(); Iterator iTer = chaves.iterator(); String chave; Pessoa p; System.out.println("\n --- HashMap de Pessoas ---"); while (iTer.hasNext()){ chave = (String) iTer.next(); p = (Pessoa) pessoas.get(chave); System.out.println("Chave: " + chave); System.out.println(p + "\n"); } } public static void removerElemento(HashMap map, String chave){ Pessoa pessoaRemovida = null; if (map.containsKey(chave)){ System.out.println("\n --- Pessoa removida do hashMap ---"); pessoaRemovida = (Pessoa) map.remove(chave); System.out.println(pessoaRemovida); } else{ System.out.println("CPF (chave) nao encontrada no hashMap"); } } } 19 Classificando Listas A classe Collections (Java.util.Collections) Arrays e implementações da interface List, usualmente, são utilizadas para armazenar objetos de mesma classe. Contudo, esses objetos são armazenados segundo a ordem de inclusão. Muitas vezes é interessante que, após a inclusão de todos os objetos, haja uma ordenação usando a "ordem natural". Para conseguirmos essa ordenação, contudo, é necessário definirmos a "ordem natural", significando que a classe a ser armazenada na List precisa implementar a interface Comparable juntamente com seu método compareTo(). Ao se analisar a documentação das implementações de List, percebe-se que não existe um método que faça a ordenação. Para fazer esta ordenação podemos empregar o método estático sort da classe utilitária Collections. Isso significa que ao executarmos o método Collections.sort(List), a lista tornar-se-á ordenada segundo a sua ordem natural. A interface Comparable (Java.lang.Comparable) Esta interface define classes que são ordenáveis, ou seja, que podem ser automaticamente ordenadas por coleções ou outras classes. A interface Comparable define um método que servirá como regra de ordenação das instâncias da classe que a implementa. Essa padronagem é denominada ordem natural, que é uma regra que deve ser utilizada para saber a precedência dos objetos. Assinatura do método: int CompareTo(Object o) Podemos exemplificar com a classe String, que implementa esta interface e sua implementação de comparação faz a análise caracter a caracter para definição da ordenação de Strings. 20 Logo, pelo conceito de ordem natural da String, a instância "automóvel" estaria localizada antes da instância "barco", pois se compararmos as primeiras letras da instância, a letra 'a' antecede a letra 'b'. Contudo, usando classes criadas durante a abstração do modelo, nem sempre temos um parâmetro adequado para comparar duas instâncias. Se tomarmos como exemplo uma classe Funcionário, possuindo os atributos nome, RG e Registro Funcional, qual dos parâmetros deve ser utilizado para definir a "ordem natural" do objeto? E se tivermos duas instâncias de funcionário "João da Silva" (homônimos), qual deve ser o próximo parâmetro de ordenação? Através da implementação desta interface é possível definir qual é a regra de ordenação natural. O método a ser implementado pela interface possui a assinatura int compareTo(Object o) usada para comparação da instância atual com qualquer outra instância da mesma classe. Um número negativo deverá ser retornado se o objeto estiver "antes" daquele passado como parâmetro, zero se forem iguais e um número positivo, se estiver "após". Vale ressaltar que o método equals da classe que implementa o Comparable deve ser coerente com o resultado do método compareTo. Portanto, se as instâncias de objetos A e B retornarem true para A.equals(B), significa que A.compareTo(B) deverá retornar zero e vice-versa. Vejamos agora um exemplo da utilização do Collections.sort(List) e a implementação do CompareTo(Object o) da interface Comparable. Para este exemplo utilizaremos Aluno.java e TesteAluno.java. duas método método classes: A classe Aluno possui dois atributos: nome e RA, e a ordem natural dos objetos desta classe foi definida da seguinte forma: Primeiramente os objetos serão ordenados pelo atributo "nome" seguindo a ordem alfabética e em caso de empate (nomes iguais) será utilizado o RA como segundo critério para desempate. 21 public class Aluno implements Comparable{ private String nome; private long RA; public Aluno(String nome, long RA){ this.nome = nome; this.RA = RA; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public long getRA() { return RA; } public void setRA(long ra) { RA = ra; } public boolean equals(Object obj){ if (obj instanceof Aluno){ Aluno aluno = (Aluno) obj; if(this.getNome().equalsIgnoreCase(aluno.getNome()) && this.getRA() == aluno.getRA()){ return true; } else{ return false; } } else return false; } public int compareTo(Object obj){ Aluno aluno = (Aluno) obj; int resp = this.getNome().compareTo(aluno.getNome()); if (resp != 0){ return resp; } else{ if (this.getRA() < aluno.getRA()){ return -1; } else if (this.getRA() > aluno.getRA()){ return 1; } else{ return 0; } } } public int hashCode(){ return (int)this.RA + this.getNome().hashCode(); } public String toString(){ String aluno = "nome: " + this.getNome() + "\n" + "RA: " + this.getRA(); return aluno; } } 22 Note que a classe Aluno implementa "Comparable" e o método compareTo(). a interface O método compareTo() faz primeiramente a comparação do atributo "nome" dos objetos e em caso de empate faz a comparação do atributo "RA". A classe "Aluno" também faz a sobrescrita dos métodos equals(), toString() e hashCode(), todos da classe Object. Veja abaixo a implementação da classe TesteAluno.java. import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; public class TesteAluno { public static void main (String[] args) { Aluno aluno1 = new Aluno("Orlando", 123); Aluno aluno2 = new Aluno("Rafael", 258); Aluno aluno3 = new Aluno("Amanda", 642); Aluno aluno4 = new Aluno("Bruna", 634); Aluno aluno5 = new Aluno("Orlando", 345); Aluno aluno6 = new Aluno("Rafaela", 942); Aluno aluno7 = new Aluno("Amanda", 650); ArrayList alunos = new ArrayList(); alunos.add(aluno1); alunos.add(aluno2); alunos.add(aluno3); alunos.add(aluno4); alunos.add(aluno5); alunos.add(aluno6); alunos.add(aluno7); System.out.println("Imprimindo alunos antes da ordenação"); Iterator iTer1 = alunos.iterator(); while (iTer1.hasNext()){ System.out.println(iTer1.next()); } Collections.sort(alunos); System.out.println("\nImprimindo alunos depois da ordenação"); Iterator iTer2 = alunos.iterator(); while (iTer2.hasNext()){ System.out.println(iTer2.next()); } } } 23 Veja abaixo a saída TesteAluno.java. gerada pela execução da classe Imprimindo alunos antes da ordenação nome: Orlando RA: 123 nome: Rafael RA: 258 nome: Amanda RA: 642 nome: Bruna RA: 634 nome: Orlando RA: 345 nome: Rafaela RA: 942 nome: Amanda RA: 650 Imprimindo alunos depois da ordenação nome: Amanda RA: 642 nome: Amanda RA: 650 nome: Bruna RA: 634 nome: Orlando RA: 123 nome: Orlando RA: 345 nome: Rafael RA: 258 nome: Rafaela RA: 942 24 Exercícios Sobre Coleções 1) Crie uma classe chamada TesteString e dentro da mesma faça o seguinte: Crie um método main; Dentro do main, crie 10 variáveis do tipo String com nomes de times de futebol; Armazene estas strings em um arrayList; Remova o elemento que está na posição seis do arrayList; Utilize o método get() para obter cada um dos elementos do arrayList e imprima os mesmos na tela. 2) Utilize a classe Java gerada no exercício anterior e substitua o método get() por um Iterator. 3) O objetivo deste exercício é implementar a relação entre uma pessoa e seus endereços. Para isto crie três classes Java: Pessoa.java, Endereco.java e TestePessoa.java. Na classe Pessoa faça o seguinte: Crie dois atributos privados: Um do tipo String para o nome da pessoa e outro do tipo ArrayList para armazenar os vários endereços da Pessoa. Crie todos os getters e setters para estes atributos. Crie um construtor alternativo para iniciar o atributo nome. Crie um método chamado "imprimirEnderecos1" e dentro do mesmo utilize o método get() do ArrayList para obter cada um dos endereços da Pessoa e imprima os mesmos na tela. Utilize toString(). Crie um método chamado "imprimirEnderecos2" e dentro do mesmo utilize um Iterator para obter cada um dos endereços da Pessoa e imprima os mesmos na tela. Utilize toString(). Na classe Endereco faça o seguinte: Crie três atributos privados: um do tipo String para o logradouro e outro também do tipo String para o complemento e um do tipo int para o número. 25 Crie os métodos getters e setters para cada um dos atributos. Sobrescreva o método toString() da classe Object para gerar uma String com os três atributos da classe. Na classe TestePessoa faça o seguinte: Crie um método main. Dentro do main crie um objeto da classe Pessoa e outro da classe ArrayList. Crie um laço de repetição e utilize os métodos da classe JOptionPane para solicitar ao usuário o logradouro, número e complemento. Armazene estas informações em um objeto da classe Endereco e armazene este endereço no ArrayList. Pergunte ao usuário se o mesmo deseja informar mais endereços e em caso afirmativo repita o processo. Se o usuário não quiser mais informar endereços, encerre o laço de repetição. O objeto do tipo ArrayList que foi utilizado para guardar os endereços deve ser armazenado no objeto da classe pessoa que foi criado anteriormente. Chame o método imprimirEnderecos1 e em seguida chame o método imprimirEnderecos2, ambos da classe Pessoa. 4) Crie uma classe Java chamada TesteHashSet.java e dentro da mesma faça o seguinte: Crie um atributo privado chamado código (int). Crie os métodos para acessar e alterar o valor deste atributo. Sobrescreva o método equals da classe Object e dentro do mesmo retorne "true" se o código passado com parâmetro for igual ao código do objeto e "false" caso contrário. Sobrescreva o método hashCode da classe Object e dentro do mesmo retorne o valor do atributo código. Crie um método main. Dentro do main faça um laço de repetição e peça para o usuário digitar um número que será código de uma pessoa. Armazene este código em um objeto da classe TesteHashSet e armazene o objeto em um hashSet. 26 5) Caso o código já tenha sido armazenado no hashSet, imprima um aviso ao usuário e peça para fornecer outro. OBS: Não se esqueça que é da própria natureza de um hashSet não permitir a inclusão de elementos repetidos. Depois que o usuário não desejar mais informar códigos, encerre o laço de repetição. Utilize um Iterator para imprimir na tela todos os códigos informados pelo usuário. Utilize a classe Pessoa.java abaixo e crie uma classe chamada TestePessoa.java. Dentro da classe TestePessoa, crie um método main e faça o seguinte: Crie vários objetos da classe Pessoa (com CPF e nome); Crie um objeto da classe HashMap; Crie um método chamado inserir que recebe como parâmetro um CPF, um objeto da classe Pessoa e o objeto da classe HashMap; Dentro deste método inseria o par CPFPessoa no HashMap. Antes de inserir certifique-se que o par CPF-Pessoa já não foi inserido anteriormente. Caso o par já tenha sido inserido, não insira o mesmo; Dentro do main faça um laço de repetição para imprimir na tela o par CPF-Pessoa; 27