Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Dúvida HashCode de objetos

Boa noite pessoal.

Reescrevi os métodos HashCode e e equals na minha classe Conta para verificar se o número da conta é igual.

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + numero;
        return result;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Conta other = (Conta) obj;
        if (numero != other.numero)
            return false;
        return true;
    }

Se no meu main eu crio um HashSet e tento adicionar neles duas contas com números igual não é possível, vou adicionar apenas um. ContaCorrente (número,agência).

 HashSet<Conta> contas = new HashSet<Conta>();

        ContaCorrente c1 = new ContaCorrente(123, 1233);
        ContaCorrente c2 = new ContaCorrente(123, 123);

Até aqui entendi, se printar "contas.size()" será retornado 1.

Abaixo, no próprio main, eu seto saldo nas duas contas.

        c1.setSaldo(1111);
        c2.setSaldo(22222);

    System.out.println(c1);
    System.out.println(c1.getSaldo());
    System.out.println(c2);
    System.out.println(c2.getSaldo());

A saída é:

br.com.alura.banco.conta.ContaCorrente@9a
1111.0
br.com.alura.banco.conta.ContaCorrente@9a
22222.0

Sem criar HashCode, as referências c1 e c2 apontam cada um para um local diferente, ou seja, uma referência para dois objetos em locais diferentes. Exemplo da saída sem implementar o HashCode em Conta:

br.com.alura.banco.conta.ContaCorrente@70dea4e
1111.0
br.com.alura.banco.conta.ContaCorrente@5c647e05
22222.0

Esqueçam a coleção HashSet que criei para guardar essas contas, porque a parte de guardar nele eu entendi, não vai guardar contas com números iguais. Vamos supor que já até tirei do código.

Minha dúvida é: Quando printo as referências c1 e c2 que possuem o mesmo número da conta (123), elas apontam para um mesmo local, quer dizer que esses dois objetos referentes a c1 e c2 foram guardados em uma mesma "caixinha" na memória por causa do HashCode que criei? Porque consigo setar o saldo e outros atributos do c1 e c2, ou seja, os dois objetos foram criados, mas agora estão se referenciando a um mesmo local.

Obrigado.

6 respostas

Boa noite Eduardo,

Na verdade, as referências c1 e c2 não apontam para o mesmo local. Motivo: você deu new para cada uma delas, logo foram reservadas posições diferentes na memóra, mesmo c1 e c2 tendo o mesmo conteúdo (mesmo número de conta).

Tanto isso é verdade que, quando você imprime c1, aparece:

br.com.alura.banco.conta.ContaCorrente@70dea4e

E quando você imprime c2:

br.com.alura.banco.conta.ContaCorrente@5c647e05

Essa string após o arroba é o endereço de memória do objeto. Como você vê, são diferentes de c1 para c2, logo falamos de objetos diferentes.

Avisa aí se ficou claro.

Abraço.

Boa noite Rafael.

A saída abaixo, que aponta para locais diferentes é quando eu retiro a implementação do HashCode da classe Conta.

br.com.alura.banco.conta.ContaCorrente@70dea4e
1111.0
br.com.alura.banco.conta.ContaCorrente@5c647e05
22222.0

Quando eu tenho o HashCode e equals na classe Conta e adiciono contas com números iguais, as referências c1 e c2 apontam para o mesmo local, mesmo eu tendo dois objetos, posso dar um getSaldo nois dois.

br.com.alura.banco.conta.ContaCorrente@9a
1111.0
br.com.alura.banco.conta.ContaCorrente@9a
22222.0
solução!

Bom dia Eduardo,

Desculpe, não tinha reparado que a primeira saída era quando você tirava sua implementação do hashCode(). Na verdade, ele estava usando o hashCode() padrão (da classe Object).

Na sua implementação, vi que você soma o número da conta com 31. Ou seja, para uma conta de número 123, o objeto vai ter hashCode igual a 154. E, em hexadecimal, o resultado é justamente 9a (o mesmo mostrado na sua segunda saída).

Ou seja: você terá dois objetos diferentes (dada a 1a saída), em posições de memória diferentes, mas com o mesmo hashCode (dada a 2a saída), por conta do critério definido por você.

Deste modo, se você inserir c1 e c2 em um HashSet, provavelmente vai haver uma colisão, logo apenas o primeiro dos objetos inseridos estará no Set.

Em tempo: uma ótima lida sobre hashCode está neste artigo. Não é extenso, está em português e é muito didático.

Avisa aí se ficou claro.

Abraço.

Entendi Rafael. Então quando eu implemento um HashCode e vou imprimir minha referência de objetos ele vai imprimir é o seu HashCode e não mais a posição da memória quando eu não tenho um HashCode implementado?

Muito obrigado.

Exato, Eduardo!

Boa noite, Eduardo e Rafael!

Em tempo, farei apenas um adendo! A saída br.com.alura.banco.conta.ContaCorrente@70dea4e nunca representa um endereço de memória! Afinal de contas, independentemente de implementarmos na raça o método hashCode() ou não, já há uma implementação padrão feita na classe Object.

Se dermos uma olhada na documentação do Java, veremos que o toString() padrão imprime o fully qualified name da classe, seguido de um @ e, por fim, o valor do hashCode daquele objeto.

Grande abraço e bons estudos!