[Resolvido] Um Set não aceita elementos iguais perante == ou .equals?

11 respostas
FredericoGenovez

Tenho um código com comportamento estranho:

public class Teste{
	
	public static void main(String [] args){
		
		Set<Conta> contas = new LinkedHashSet<>();
		
		Conta c1 = new Conta();
		Conta c2 = new Conta();
		c1.nome = "a";
		c2.nome = "a";
		
		System.out.println(contas.add(c1));//imprime true
		System.out.println(contas.add(c2));//imprime true novamente mesmo com os elementos sendo iguais, e eu implementei o metódo equals...
		
		System.out.println("Eles são .equals ? "+c1.equals(c2));//imprime true
		System.out.println("Eles são == ?"+(c1 == c2));//imprime false
				
	}
	
}
class Conta{
	
	String nome;
	
	public boolean equals(Object o){
		if(o instanceof Conta)
			if(((Conta)o).nome.equals(this.nome))
				return true;
		return false;
	}
	
}

??? Como consegui inserir dois elementos (equals) em um Set? o Set verifica igualdade de referências ???

11 Respostas

gustavocoolt

Qual sua dúvida?

System.out.println("Eles são .equals ? "+c1.equals(c2));//imprime true

O trecho acima imprime true pois o equals compara o conteudo…

System.out.println("Eles são == ?"+(c1 == c2));//imprime false

O trecho acima imprime false pois == esta comparando a referencia dos objetos…

FredericoGenovez

A dúvida é, um Set permite a inserção de objetos Iguais? Se não permite porque no código que eu postei consegui inseri dois objetos iguais?? Para o Set os Objetos são iguais (==) ou iguais (equals) ???

gustavocoolt

Os objetos foram considerados diferentes pelo operador ==, embora contenham conteudos idênticos, pois a referência aos objetos na memória heap é diferente.

FredericoGenovez

Eu sei disso, a pergunta é a seguinte, em um conjunto Set eu não posso adicionar elementos iguais pois o um Set é uma representação dos conjuntos numéricos, mais se meus objetos são iguais, mesmo que não ocupem o mesmo espaço na memória o Set não vai os considerar iguais? ele usa a comparação por referências e não o metódo equals? tem algo errado aí pois se ele fosse usar a igualdade por referências não iria haver a necessidade do metódo equals se chamar equals, pois se ele se chama equals em Object e eu reescrevo e para que os frameworks e bibliotecas o chamem se não eu poderia criar meu proprio método de igualdade…
Eu estou fazendo uns testes aqui com a classe String por exemplo funcionou normalmente ele compara se os elementos são iguais com o metódo equals, mas na minha classe ainda não consegui achar o problema…

FredericoGenovez

Veja outro exemplo do problema…

import java.util.Set;
import java.util.HashSet;

public class Teste{
	
	public static void main(String [] args){
		
		Set<A> as = new HashSet<>();
                
		A a = new A();
		A b = new A();
		A c = new A();
		a.nome = "A";
		b.nome = "A";
		c.nome = "c";
		
		System.out.println(a.equals(b));//Imprime true mais se eles são iguais como nas linhas abaixo eu adiciono os dois na coleção?
		
		System.out.println(as.add(a));
		System.out.println(as.add(b));
		System.out.println(as.add(c));
		
	}
	
}
class A{
	
	String nome;
	
	public boolean equals(Object o){
		return ((A)o).nome.equals(this.nome);
	}

}
jamirdeajr

Olá,
Você precisa fazer override do hashcode... O add do set vai chamar ele para fazer a comparação...

class Conta{  
         
        String nome;  
        @Override 
        public boolean equals(Object o){  
            if(o instanceof Conta)  
                if(((Conta)o).nome.equals(this.nome))  
                    return true;  
            return false;  
        }  
        
        @Override
        public int hashCode() {
            return nome.hashCode();
        }
    }
gustavocoolt

desculpa, entendi sua duvida… e realmente só faltou vc deve reescrever o hascode…
abraço

FredericoGenovez
jamirdeajr:
Olá, Você precisa fazer override do hashcode... O add do set vai chamar ele para fazer a comparação...
class Conta{  
         
        String nome;  
        @Override 
        public boolean equals(Object o){  
            if(o instanceof Conta)  
                if(((Conta)o).nome.equals(this.nome))  
                    return true;  
            return false;  
        }  
        
        @Override
        public int hashCode() {
            return nome.hashCode();
        }
    }

É isso mesmo, funcionou aqui agora, vou dar umas estudada no método hashCode, pois não sabia que o Set usava ele na comparação, você sabe me explicar o motivo do uso dele para comparação?

FredericoGenovez

Achei uma explicação, obrigado ai a ajuda gente…

gustavocoolt

O hashCode é um método que retorna um código hash de um objeto… assim é definido que posição que o objeto será salvo, se outro objeto chegar na posição ja salva, ele substitui.
OBS: Ele nao precisa percorrer toda a lista verificando… ele vai direto na posição que o hash retornou, ganhando performance.

jamirdeajr

Acho que a melhor explicação está no livro Effective Java, que copio aqui em uma tradução livre:
“Item 9: Sempre sobrescreva hasCode quando sobrescrever equals
Uma fonte comum de bugs é o esquecimento de fazer override do método hashCode. Você precisa sobrescrever o hashCode em toda classe que sobrescrever equals.
Não fazer resultará na violação do contrato geral para Object.hashCode, que fará com que sua classe não funcione corretamente em conjunto com as coleções baseadas em hash, incluindo HashMap, HashSet e HashTable.

Legal, até eu entendi melhor isso agora!

Criado 28 de outubro de 2012
Ultima resposta 28 de out. de 2012
Respostas 11
Participantes 3