O código abaixo gera como saída 3. Isso quer dizer que o método equals da classe WrappedString não está sendo chamado (porque se estivesse, acho que a saída deveria ser 2). Para provar isso, coloquei um “System.out.printf” no método.
import java.util.*;
public class WrappedString extends Object
{
private String s;
public WrappedString(String s){ this.s = s;}
public static void main(String args[]){
HashSet<Object> hs = new HashSet<Object>();
WrappedString ws1 = new WrappedString("aardvark");
WrappedString ws2 = new WrappedString("aardvark");
String s1 = new String("aardvark");
String s2 = new String("aardvark");
hs.add(ws1); hs.add(ws2); hs.add(s1); hs.add(s2);
System.out.println( hs.size() );
}
@Override
public boolean equals(Object o){
System.out.printf("Chamou!\n");
WrappedString outro = (WrappedString) o;
if( s.equals(outro.s) ) return true;
return false;
}
}
A minha pergunta é: por que esse método equals que eu sobreescrevi na classe WrappedString não está sendo chamado?
Obrigado!
Entendi, realmente eu estava sobrecarregando ao invés de sobreescrever. Eu alterei meu código agora. Porém, ele continua gerando 3 na saída. Não era para gerar 2???
Como assim? Se eu já sobreescrevi o método equals então não deveria estar usando o método sobreescrito? Tem outra coisa estranha. Nem todos os objetos que colocarmos naquele HashSet poderão ter o cast do equals que eu sobreescrevi feito (pois nem todos os objetos são da classe WrappedString.
A minha pergunta agora é: qual equals a classe HashSet está chamando para ver se o elemento que eu estou inserindo já está no conjunto?
Olá amigo
eu testei aqui e quando eu sobescrevi o hashcode o código funcionou corretamente, mas msm assim me pareçe estranho funcionar só depois de sobescrever hashcode porq pelo oque eu sei ele testa o hashcode por último
import java.util.HashSet;
public class WrappedString
{
private String s;
public WrappedString(String s){ this.s = s;}
public static void main(String args[]){
HashSet<Object> hs = new HashSet<Object>();
WrappedString ws1 = new WrappedString("aardvark");
WrappedString ws2 = new WrappedString("aardvark");
String s1 = new String("aardvark");
String s2 = new String("aardvark");
System.out.println(hs.add(ws1));
System.out.println(hs.add(ws2));
System.out.println(hs.add(s1));
System.out.println(hs.add(s2));
System.out.println( hs.size() );
}
public boolean equals(Object o){
System.out.printf("Chamou!\n");
if(o instanceof WrappedString) {
WrappedString outro = (WrappedString) o;
if(this.s.equals(outro.s) )
return true;
}
return false;
}
public int hashCode() {
return s.hashCode();
}
}
Quer dizer então que a classe HashSet vai sempre chamar o equals da classe do objeto que está sendo inserido naquele momento?? No caso, na primeira inserção ela não chama nenhum equals porque ainda não existe nenhum elemento no conjunto. Na segunda, HashSet chama o equals que eu sobreescrevi (porque o objeto que está sendo inserido é do tipo WrappedString). E finalmente, na terceira e na quarta inserção, HashSet chama o equals da classe String. É isso?
sim
para funcionar certo vc vai ter que sobescrever o método equals e hashcode porq senão vc não vai conseguir impedir a inserção de objetos iguais…
porq a implementação padrão de equals simplesmente compara as referências de 2 objetos ou seja é semelhante ao operador ==
Bom, a regra prática, conforme K&B, Livro de Certificação, página 306, diz que o método equals() e hashcode() estão vinculados por um contrato de associação, portanto, você deve subscrever os dois métodos. Note que o método equals() não possiu implementação na classe Object, e que apenas o método hashcode() está implementado na mesma, assim, quando hashcode() não é sobreescrito em uma determinada classe não há polimorfismo e método original será chamado. Ocorre que o método original de hashcode() tem sua implementação específica, e isto significa que este pode retornar o MESMO valor para objetos considerados DIFERENTES. Por fim, o seu objeto WrappedString é quase sempre considerado diferente, já que o hashcode() original de Object foi chamado, pois retornou valores de hashing diferentes, o que permitiu a duplicata deste objeto no seu HashSet. Diferentemente do que ocorreu com os objetos String, uma vez que estes possuiem implementações apropriadas de hashcode() e equals().
Pelo que sei ele, o Set chama primeiro o hashCode(), e neste caso objetos distintos podem ter o mesmo hashCode(), embora não é aconselhado por causa de performance.
Caso os objetos possuem o mesmo hashCode(), ai sim o Set, chama o equals() para verificar se realmente se os objetos são os mesmos.
Bom!.. Simples! pelo que eu vi, vc não esta chamando o equals da classe que pretende sobrescreve-lo.
Vc esta chamando-o de uma classe String (variavel: “s”). s.equals(outro.s). Assim como o vmsb11 demonstrou, mas o problema não é solucionado após implementar hashcode e sim na forma de escrever equals (this.s.equals(outro.s)).
Dorpho acho que o problema foi resolvido com o hashCode sim, fiz os testes aqui e so foi verificado os objetos iguais quando eu sobreescrevi o hashCode
Td bem, acredito que tenha sido resolvido. Contudo, o primeiro código não é uma implementação correta.
É necessário o teste É-UM antes, pois caso não seja um objeto WrapperString ele usará o equals patrão do objeto String, sendo assim “Chamou!” é mostrado apenas uma vez, como foi mostrado anteriormente.
creio que seja porq na implementação do HashSet ele chama o hashcode do objeto que vc quer inserir e então ele só chamará o método equals quando vc encontrar um hashcode igual ao do objeto que vc quer inserir ai como são iguais ele chamará o método equals.
Mas vmsb “notreve” tem o mesmo hashCode que “everton” então o segundo objeto e o primeiro ele chamaria equals, e o terceiro e o segundo ele tb chamaria equals n?