Dúvida HashSet + hashCode [RESOLVIDO]

3 respostas
rickfrocha

Boa noite pessoal, tudo bom?

estou estudando para a certificação e fiquei em dúvida com uma situação. Imaginem que tenho o seguinte código:

class A{
    private String nome;
    public int hashCode(){
        return 10;
    }

   public boolean equals(Object o){
       return false;
   }
}


public class teste{
    public static void main(String[] args){
         Set set = new HashSet();
         A a1 = new A();  A a2 = new A(); A a3 = new A();
         set.add(a1 ); set.add(a2); set.add(a3); 
         system.out.println(set.size());
         set.remove(a1);
         system.out.println(set.size());
    }
}

Não levando em conta o contrato do equals e hashCode, e pensando que o hashCode é utilizado para organizar e buscar o elemento dentro da coleção, neste exemplo todos os elementos tem mesmo hashCode e o método equals retorna false, como que o objeto set consegue eliminar o objeto a1?

Desde já obrigado. :slight_smile:

3 Respostas

A

Ok , boa questão , quase que filosófica … bem analisando o código através do depurador (Step over, step into, etc) vi que numa parte do código ele realmente entra no método equals () que vc sobrescreveu e este retorna false , na medida em que vai testando os valores. só que além deste teste do equals tem outro donde ele compara o hash e a chave que vc passou , estes dois combinados conseguem encontrar o elemento que vc passou a1. Aqui está o método em questão que é chamado :

final Entry<K,V> removeEntryForKey(Object key) {

int hash = (key == null) ? 0 : hash(key.hashCode());

int i = indexFor(hash, table.length);

Entry<K,V> prev = table[i];

Entry<K,V> e = prev;
while (e != null) {
        Entry<K,V> next = e.next;
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k)))) {
            modCount++;
            size--;
            if (prev == e)
                table[i] = next;
            else
                prev.next = next;
            e.recordRemoval(this);
            return e;
        }
        prev = e;
        e = next;
    }

    return e;
}

E está e a comparação que te falo:

if (e.hash == hash &&
((k = e.key)
== key || (key != null && key.equals(k))))

onde o equals é sim o metodo que sobrescrevestes e o key é o objeto passado para este método …

Entendeu alguma coisa ??? confesso que não entendi 100% tamb … Fico no aguardo de mais esclarecimentos .

rickfrocha

alexmonassa:
Ok , boa questão , quase que filosófica … bem analisando o código através do depurador (Step over, step into, etc) vi que numa parte do código ele realmente entra no método equals () que vc sobrescreveu e este retorna false , na medida em que vai testando os valores. só que além deste teste do equals tem outro donde ele compara o hash e a chave que vc passou , estes dois combinados conseguem encontrar o elemento que vc passou a1. Aqui está o método em questão que é chamado :

final Entry<K,V> removeEntryForKey(Object key) {

int hash = (key == null) ? 0 : hash(key.hashCode());

int i = indexFor(hash, table.length);

Entry<K,V> prev = table[i];

Entry<K,V> e = prev;
while (e != null) {
        Entry<K,V> next = e.next;
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k)))) {
            modCount++;
            size--;
            if (prev == e)
                table[i] = next;
            else
                prev.next = next;
            e.recordRemoval(this);
            return e;
        }
        prev = e;
        e = next;
    }

    return e;
}

E está e a comparação que te falo:

if (e.hash == hash &&
((k = e.key)
== key || (key != null && key.equals(k))))

onde o equals é sim o metodo que sobrescrevestes e o key é o objeto passado para este método …

Entendeu alguma coisa ??? confesso que não entendi 100% tamb … Fico no aguardo de mais esclarecimentos .

Fala Alex, tudo bom?

cara muito obrigado pela ajuda, entendi perfeitamente …

Internamente ele faz o seguinte:

–> Recebe objeto key
–> Procura os elementos com mesmo hashCode do objeto Key
–> Itera elementos com mesmo hashCode
–> Pra cada elemento ele verifica: referencia do objeto Key passada no método é igual do objeto da iteração(apontam para mesmo end. de memoria) OU
são equivalente iguais (método equals).

Acho que esse é o pulo do gato …

Muito obrigado pelo esclarecimento.

abs

  1. :smiley: :slight_smile:
A

rickfrocha:
alexmonassa:
Ok , boa questão , quase que filosófica … bem analisando o código através do depurador (Step over, step into, etc) vi que numa parte do código ele realmente entra no método equals () que vc sobrescreveu e este retorna false , na medida em que vai testando os valores. só que além deste teste do equals tem outro donde ele compara o hash e a chave que vc passou , estes dois combinados conseguem encontrar o elemento que vc passou a1. Aqui está o método em questão que é chamado :

final Entry<K,V> removeEntryForKey(Object key) {

int hash = (key == null) ? 0 : hash(key.hashCode());

int i = indexFor(hash, table.length);

Entry<K,V> prev = table[i];

Entry<K,V> e = prev;
while (e != null) {
        Entry<K,V> next = e.next;
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k)))) {
            modCount++;
            size--;
            if (prev == e)
                table[i] = next;
            else
                prev.next = next;
            e.recordRemoval(this);
            return e;
        }
        prev = e;
        e = next;
    }

    return e;
}

E está e a comparação que te falo:

if (e.hash == hash &&
((k = e.key)
== key || (key != null && key.equals(k))))

onde o equals é sim o metodo que sobrescrevestes e o key é o objeto passado para este método …

Entendeu alguma coisa ??? confesso que não entendi 100% tamb … Fico no aguardo de mais esclarecimentos .

Fala Alex, tudo bom?

cara muito obrigado pela ajuda, entendi perfeitamente …

Internamente ele faz o seguinte:

–> Recebe objeto key
–> Procura os elementos com mesmo hashCode do objeto Key
–> Itera elementos com mesmo hashCode
–> Pra cada elemento ele verifica: referencia do objeto Key passada no método é igual do objeto da iteração(apontam para mesmo end. de memoria) OU
são equivalente iguais (método equals).

Acho que esse é o pulo do gato …

Muito obrigado pelo esclarecimento.

abs

  1. :smiley: :slight_smile:

ok , parece que eh isto mesmo ? mas porque ele usa o HashMap ??? Outra questão filosófica … ???

Ah detalhe neste exemplo , está seguindo exatamente a regra de sobrescrita do hashcode e do equals. Só que pra maioria das pessoas que fariam esta questão iriam errar pois iriam pensar que nunca passaria no teste equals e nunca nenhum objeto seria inserido , somente aqueles que tivessem conhecimento em detalhes da implementação do Hashset. Pois como vimos pelo depurador O HashSet usa um método do HashMap , além do método que sobrescreves (equals e hashcode) . Acho q poucos que estudam certificação saberiam disso e muitos errariam a questão , eu acho assim …

Criado 22 de março de 2013
Ultima resposta 22 de mar. de 2013
Respostas 3
Participantes 2