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.
Não funcionou. Gerou o seguinte erro em tempo de compilação:
WrappedString.java:19: method does not override or implement a method from a supertype
@Override
^
1 error
Jairo_Junior1
Você não está sobreescrevendo o método equals, está sobrecarregando.
T
TiagoTC
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???
peczenyj
Era para dar erro. O HashSet usa o equals que recebe um objeto, não o que vc esta declarando
T
TiagoTC
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?
V
vmsb11
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
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?
V
vmsb11
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 ==
sech777
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().
Filipe A. Pinheiro
A
Astork
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.
Att
DorPho
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)).
Grande abraço!
evertonsilvagomesjav
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
DorPho
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.
evertonsilvagomesjav
Deixa eu aproveitar o tópico e fazer uma pergunta, sobre o codigo abaixo:
publicstaticvoidmain(String[]args){//new Cat().go(null);HashSet<Object>teste=newHashSet<Object>();teste.add(newCat("everton"));teste.add(newCat("notreve"));teste.add(newCat("everton"));teste.add(newCat("joao"));}publicbooleanequals(Objecto){System.out.printf("equals\n");if(oinstanceofCat&&this.nome.equals(((Cat)o).nome))returntrue;returnfalse;}publicinthashCode(){// método que olha o hash da variavel nome.System.out.printf("hash\n");returnthis.nome.hashCode();}
Pq o codigo abaixo imprime:
hash
hash
hash
equals
hash
Em todos objetos ele nao faz chamada a equals e hash não??
V
vmsb11
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.
evertonsilvagomesjav
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?
V
vmsb11
aqui em casa não produziram o msm hashcode…
olha o teste que eu fiz:
ou seja ele usa exponenciação em conjunto com o valor ascii do caracter na implementação ou seja imagine a string “ab” a impl possivelmente será hash = valorAsciiA * 31 ^ tamanho - 1 + valorAsciiB * 31 ^ tamanho - 2 onde ^ = exponenciação
então a string “ba” irá retornar um hashcode diferente porq no cálculo é relacionado o código ascii com a exponenciação porq a fórmula seria esta: hash = valorAsciiB * 31 ^ tamanho - 1 + valorAsciiA * 31 ^ tamanho - 2
conseguiu enxergar que o resultado será diferente
faça o calculo no papel que vc conseguirá enxergar
assuma que o valor ascii de a é 97 e b é 98 só para testar.
só corrigindo é hash = valorAsciiA * 31 ^ tamanho - 1 + valorAsciiB * 31 ^ tamanho - 2 em vez de hash = valorAsciiA * 31 ^ 0 + valorAsciiB * 31 ^ 1
T
TiagoTC
Como assim everton? A idéia é que a função hash tenha o menor número possível de colisões mesmo. Eu entendi o seguinte:
everton tenta entrar no conjunto. É calculado o hash. O hash não bate com nenhum elemento do conjunto (pois não há nenhum elemento no conjunto ainda). Logo, não é preciso compará-lo com equals. everton é adicionado no conjunto.
notreve tenta entrar no conjunto. É calculado o hash. O hash não bate com o hash de everton, então, não é preciso chamar equals (os objetos já são diferentes). notreve é adicionado no conjunto.
everton tenta entrar no conjunto. É calculado o hash. Já existe um elemento no conjunto que possui o mesmo hash do novo everton (esse elemento é o velho everton), logo, é necessário compará-los com equals também. O equals então é chamado e retorna verdadeiro. Logo, esse novo everton não é adicionado no conjunto.
joão tenta entrar no conjunto. É calculado o hash. Os hash de joão não bate com o hash de everton nem com o de notreve. Logo, eles já são diferentes. Não é preciso compará-los com equals. joão é adicionado no conjunto.
V
vmsb11
exatamente isso TiagoTC por isso que o método hashcode utiliza exponenciação no calculo por isso que quando alteramos a ordem das strings o resultado será diferente
evertonsilvagomesjav
De acordo com as explicações que vcs deram eu entendi perfeitamente e agredeço por sanar minha duvida, agora se eu nao me engano ou eu nao entendi bem e vou ler de novo no livro da Kathy Sierra estava falando que o hashCode de “amy” e “may” seriam os mesmos agora não sei se entendi errado ou estava isso mesmo, chegando em ksa vou ler novamente, mas de qualquer forma vlwww pelas explicações!!!