Interface para o HashSet

Quais as interfaces necessárias a classe precisa implementar para que possa ser usada num HashSet, evitando objetos repetidos.

A classe em questao chama-se Habilidade e se o campo codHabilidade for igual considera-se o objeto igual.

Eu ja implementei o metodo equals retornando true se os codHabilidade dos objetos comparados forem iguais, já implementei a interface Comparable (método compareTo retornando 0 caso os codHabilidade sejam iguais), e ainda está colocando elementos repetidos no HashSet.

E ai rapaz… tudo bem?!

Cara… não entendi seu problema não! Tente explicar melhor… :slight_smile:

No aguardo…

[quote=hill]Quais as interfaces necessárias a classe precisa implementar para que possa ser usada num HashSet, evitando objetos repetidos.

A classe em questao chama-se Habilidade e se o campo codHabilidade for igual considera-se o objeto igual.

Eu ja implementei o metodo equals retornando true se os codHabilidade dos objetos comparados forem iguais, já implementei a interface Comparable (método compareTo retornando 0 caso os codHabilidade sejam iguais), e ainda está colocando elementos repetidos no HashSet.[/quote]

Um HashSet é um HashMap onde chave == valor.
Para inserir elementos em um HashSet você precisa implementar corretamente public boolean equals (Object o) e public int hashCode(). Não é preciso implementar Comparable.

[quote=thingol]Um HashSet é um HashMap onde chave == valor.
[/quote]

Huh? Não entendi. Não é o HashMap que usa um HashSet para guardar chaves? Aí um HashSet é um HasMap, que usa um HashSet, que é um HashMap, que usa um HashSet, que é um… :smiley:

Hill, posta teu equals e hashCode ae…

[quote=renato3110][quote=thingol]Um HashSet é um HashMap onde chave == valor.
[/quote]

Huh? Não entendi. Não é o HashMap que usa um HashSet para guardar chaves? Aí um HashSet é um HasMap, que usa um HashSet, que é um HashMap, que usa um HashSet, que é um… :smiley:
[/quote]

Bom, eu fui pela descrição do Javadoc (This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. This class permits the null element.).
Vou dar uma olhada no fonte das duas classes para ver o que veio primeiro, o ovo (HashSet) ou a galinha (HashMap).

public class HashSet extends AbstractSet
		     implements Set, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
	map = new HashMap();
    }

Aham, nem o ovo nem a galinha - talvez um biscoito e uma jarra de biscoitos; a implementação da Sun de um HashSet contém um HashMap (ele não é um HashMap).

Que louco isso. Mas o HashMap não contém um HashSet também? Tô sem o fonte do JDK…

Desculpe, não entendi o porque de implementar o metodo int hashCode. Como acontece essa distinção entre objetos quando sao colocados no Set ? Não eh através do metodo boolean equals(Object o) ? Porque se fosse assim, da forma como esta implementado o equals, duas Habilidade com codHabilidade iguais não poderiam ser inseridas, não eh mesmo ? E como é feita a implementação do método int hashCode nessa lógica simples do meu problema ?

public boolean equals(Object obj) { Habilidade h = (Habilidade) obj; boolean retValue = false; if(getCodHabilidade().equals(h.getCodHabilidade())){ retValue = true; } return retValue; }

Porque quando você precisa pesquisar seus objetos, que por um acaso estão armazenados numa estrutura de dados chamada tabela de hash,
o hashCode() agiliza a busca, ou faz ela não funcionar…

Seus Habilidade iguais devem estar sendo colocados no set porque retornam hash codes diferentes para objetos iguais.

Seu equals pode ser melhorado. Resumindo, o hash code deve retornar um número baseado na identidade do objeto, ou seja, baseado no equals(). Repita isso como um mantra:

Ao alterar equals(), provavelmente você precisa fazer o mesmo com hashCode().

Eu tava escrendo um texto sobre isso, talvez ano que vem tenha algo pronto :mrgreen: Você tá precisando ler um material sobre igualdade de objetos em Java, incluindo o equals() e o hashCode().

Tinha um tópico maneiro que acho que sumiu, mas olha esse link aqui por enquanto, e googla também.

http://www.universiabrasil.net/mit/6/6.170/pdf/6.170_lecture-09.pdf

Acho que a Mundo Java edição 9 tem um artigo sobre isso também…

Rode este programa. Ele demonstra o que ocorre se uma classe não define hashCode direito.

import java.util.*;

/**
 * Esta classe implementa equals e hashCode.
 */
class Cliente {
    private String nome = "";
    private String endereco = "";
    public Cliente(String pNome, String pEndereco) { nome = pNome; endereco = pEndereco; }
    public String getNome() { return nome; } public void setNome(String pNome) { nome = pNome; }
    public String getEndereco() { return endereco; } public void setEndereco(String pEndereco) { endereco = pEndereco; }
    public String toString() { return "nome=" + nome + ", endereco=" + endereco; }
    public boolean equals (Object o) {
        if (!(o instanceof Cliente)) return false;
        if (o == this) return true;
        Cliente c = (Cliente) o;
        // só para simplificar estou supondo que nenhum dos campos é null
        return nome.equals(c.getNome()) && endereco.equals(c.getEndereco());
    }
    public int hashCode() {
        int ret = nome.hashCode();
        ret = ret * 37 + endereco.hashCode();
        // se houver mais campos, vá repetindo a expressão acima "ret = ret * 37 + hashCode do proximo campo"
        // por exemplo, ret = ret * 37 + telefone.hashCode();
        return ret;
    }
}

/**
 * Esta classe implementa equals, mas não hashCode.
 */
class Cliente2 {
    private String nome = "";
    private String endereco = "";
    public Cliente2(String pNome, String pEndereco) { nome = pNome; endereco = pEndereco; }
    public String getNome() { return nome; } public void setNome(String pNome) { nome = pNome; }
    public String getEndereco() { return endereco; } public void setEndereco(String pEndereco) { endereco = pEndereco; }
    public String toString() { return "nome=" + nome + ", endereco=" + endereco; }
    public boolean equals (Object o) {
        if (!(o instanceof Cliente2)) return false;
        if (o == this) return true;
        Cliente2 c = (Cliente2) o;
        // só para simplificar estou supondo que nenhum dos campos é null
        return nome.equals(c.getNome()) && endereco.equals(c.getEndereco());
    }
}

class TestHashSet {
    public static void main(String[] args) {
        HashSet<Cliente> clientes = new HashSet<Cliente>();
        clientes.add (new Cliente ("Luis Inacio", "Palacio da Alvorada"));
        clientes.add (new Cliente ("Fernandinho Beira-Mar", "Presidente Bernardes"));
        clientes.add (new Cliente ("Fernandinho Beira-Mar", "Presidente Bernardes"));
        System.out.println (clientes); // deve aparecer só uma vez o sr. Fernandinho
        HashSet<Cliente2> clientes2 = new HashSet<Cliente2>();        
        clientes2.add (new Cliente2 ("Luis Inacio", "Palacio da Alvorada"));
        clientes2.add (new Cliente2 ("Fernandinho Beira-Mar", "Presidente Bernardes"));
        clientes2.add (new Cliente2 ("Fernandinho Beira-Mar", "Presidente Bernardes"));
        System.out.println (clientes2); // O sr. Fernandinho aparece duas vezes.
    }
}

Muito obrigado rapaziada, isso resolveu o problema aqui.
Vou pesquisar + sobre esse assunto, mas o q vcs postaram fez toda a diferença.
[]´s[size=9][/size]