Certificação Java SCJA
Prof.: Aníbal Fernandes
https://sites.google.com/site/wizard2javadevelopers/
10/05/2012
CONJUNTOS
O método
equals
Muito utilizado em programação. Tem por finalidade verificar se
dois objetos são iguais retornando um valor booleano, onde true
significa que o objeto é igual e false que o objeto é diferente.
public class Pessoa { private String nome; private String cpf; private Integer idade;
public Pessoa(String nome, String cpf) { this.nome = nome;
this.cpf = cpf; }
public Integer getIdade() { return idade;
}
public void setIdade(Integer idade) { this.idade = idade;
}
public String getNome() { return nome;
}
public String getCpf() { return cpf;
} }
@Override
public boolean equals(Object objeto) { if(objeto instanceof Pessoa ) {
if( ((Pessoa) objeto).nome == this.nome) { if( ((Pessoa) objeto).cpf == this.cpf) {
if( ((Pessoa) objeto).idade == this.idade) { return true; } } } } return false; }
Por que sobrescrever equals?
Para saber se dois objetos diferentes
(mas do mesmo tipo) possuem
Por que sobrescrever equals?
A resposta será
“b1 é igual a b2?? true” Entretanto, comentarmos o método equals a resposta será
“b1 é igual a b2?? false”. Isso ocorre porque na classe Object o método equals é implementado da seguinte maneira.
O contrato do método
equals
deve ser
- Reflexivo
Deve retornar um valor booleano true se x.equals(x)
- Simétrico
Deve retornar um valor booleano true se x.equals(y) == y.equals(x)
-Transitivo
se ( (x.equals(y) == true) && (y.equals(z) == true)) então
x.equals(z) deve retornar um valor booleano true
-Consistente
Deve sempre retornar true ou false, desde que nenhuma
propriedade do objeto tenha sido alterada
Para qualquer referencia de x que não seja null, x.equals(null)
deve sempre retornar false.
O método hashCode
Retorna o um valor int do código hashing do objeto.
O método hashCode tem sua assinatura definida como:
Por que sobrescrever hashCode?
Para melhorar o desempenho principalmente em coleções.
Exemplo:
Se o método hashCode não for sobreescrito, toda vez que o método for
invocado, retornará um valor int aleatório, gerando resultados incorretos.
Exemplo: Sobrescrevendo o método hashCode()
A resposta será “O valor de hashCode é: 23″, e se você comentar o método
hashCode a resposta pode ter diversos valores como “O valor de hashCode é: 1671711″ ou “O valor de hashCode é: 11394033″ ou “O valor de hashCode é: 4384790″.
O trecho de código
“numero * 23″ no exemplo é apenas um exemplo.
Pode-se usar qualquer número que possa ser realizado uma operação matemática com inteiros.
O contrato de hashCode deve ser:
- Constante
Deve retornar sempre o mesmo valor int para o mesmo objeto,
contando que nenhum valor usado na comparação de equals
tenha sido alterado
Se x.hashCode() retorna 10, então se x.hashCode() for chamado
novamente deve retornar 10
-Igual para objetos iguais
x.equas(y) então x.hashCode() e y.hashCode() devem ter o
mesmo valor
-Não é obrigatório ser diferente para objetos diferentes
Se x.equals(y) for false, pode-se ter x.hashCode() == y.hashCode()
ou x.hashCode() != y.hashCode()
Incluir variáveis transient em métodos hashCode é valido mas não
recomendado devido a serialização.
O método toString
Retorna uma “representação em texto” do objeto. O método toString tem sua assinatura definida como:
Por que sobrescrever toString?
Para obter um resultado com facilidade de compreensão relacionado aos objetos da sua classe.
O código acima imprimirá “Resultado com toString implícito: Classe A”, e “Resultado com
toString explicito: Classe A”. Não há necessidade de se declarar explicitamente a invocação do método toString, lembrando que foi omitido a implementação da ClasseA e que seu método toString esteja implementado de forma correta e com um retorno com valor “Classe A”.
E se Não sobrescrevermos o método toString?
Não teremos uma boa representação de seu objeto.
Será impresso
“Classe A com número de valor 1″, e se
comentarmos
o método toString terá um resultado parecido com “A@17″, onde o valor antes do “@” representa o nome da classe e o valor após o “@” representa um código hexa do seu valor hashing.
A implementação do método na classe Object.
Podemos ver que equals, hashCode e toString devem ser
implementados em seus objetos, e que equals e hashCode são
fundamentais para a performance de coleções. Vimos também
que toString faz uma representação em forma de texto do
objeto e que pode ser invocado tanto implicitamente quanto
explicitamente.
Hashtable ou HashMap e hashCode(): Como e porque usar
Conforme observamos nas aulas anteriores, a classe
java.util.Hashtable é uma estrutura de Collection de Java,
que serve para armazenar outras classes, objetos ou
atributos.
Coisas que um array ou um Vector também o fazem.
Entretanto, a utilidade do Hashtable se encontra no fato
de que pode-se “indexar” um objeto dando uma
chave/índice para ele para que mais tarde possamos
utilizar essa chave para recuperar o objeto em questão.
Um exemplo simples e prático de uso seria para o sistema
de busca do Detran, onde cada veículo possui um código
no caso sua placa (chave primária no BD) para busca.
O tipo de objeto/classe utilizado tanto para chave (key)
quanto para o valor, podem ser quaisquer objetos ou
classes, porém,
os resultados mais interessantes são
obtidos quando se usa um tipo padronizado de
chave/valor
.
No exemplo a seguir utilizaremos a chave como String e
o objeto armazenado como um objeto da classe
customizada Livro para melhor demonstrar o potencial
dos Hashtables.
No exemplo estilizamos uma String como código e chave do livro, o que é mais coerente na realidade de uma biblioteca. Na verdade nós parametrizamos o Hashtable
(Hashtable<String, Livro>), colocando o nome das classes usadas como chave e valor, respectivamente, entre as tags < >.
A chave é uma String e o objeto armazenado é a classe Livro que criamos, dessa forma quando usarmos o método hash.get devemos enviar uma String com o código do livro que desejo e esse método retornará um objeto do tipo Livro automaticamente. Repare que neste exemplo não é necessário fazer um casting ao usar o método get como no exemplo anterior.
Os parâmetros genéricos também são úteis para validar seu código em tempo de
compilação, ou seja, se você tentar inserir um Integer como uma chave no Hashtable, o compilador indicará um erro.
O HashMap possui basicamente as mesmas funcionalidades do que Hashtable, só que não provê integridade se seus objetos são acessados por Threads concorrentes, ao contrário do Hashtable. Por causa disso a estrutura HashMap é um pouco mais rápida para acesso aos objetos. Se você Não utilizar threads aplique HashMap, do contrário, se o seu aplicativo utiliza várias Threads concorrentes faça uso do Hashtable.
Hashtables e HashMap são geralmente usados para implementar o conceito de cache, ou seja, eu posso utilizar o objeto de que necessito bastando eu possuir alguma informação que o identifique, sem ter que carregá-lo novamente do banco de dados ou do sistema de arquivos, o que pode afetar a performance do sistema, conforme o caso.
Importante: se você usa um objeto que você mesmo criou como chave de um
hashtable/hashmap, você precisa criar explicitamente um método hashCode() na sua
classe (além do óbvio método equals()), do contrário o método get pode não encontrar seu objeto e retornar null, mesmo que ele já exista como uma key dentro do
Hashtable/HashMap, o que me aconteceu ontem e me levou a criar esse post, depois de perder muito tempo.
O hashCode() é um método que retorna um valor int, calculado a partir dos atributos que sua classe possui. Dois objetos onde equals() retorna true devem gerar obrigatoriamente o mesmo hashcode, mas a recíproca não é verdadeira, ou seja, só porque dois objetos
podem ter o mesmo hashCode não garante que eles sejam iguais (que o método equals() retorne true). Geralmente aparece um aviso em amarelo na IDE em cima do método
equals, avisando que a classe não implementou o método hashCode(), é só clicar que então ele é gerado. Lembre-se: IDEs são suas amigas!!