Pergunta

Em Java, eu tenho um Vertex subclasse da Point3f classe Java3D. Agora calcula Point3f equals() com base nos valores de suas coordenadas, mas para minha classe Vertex eu quero ser mais rigorosa: dois vértices são apenas iguais se eles são o mesmo objeto. Tão longe, tão bom:

class Vertex extends Point3f {

    // ...

    public boolean equals(Object other) {
        return this == other;
    }
}

Eu sei que isto viola o contrato de equals(), mas desde que eu só vou comparar vértices para outros vértices esse não é um problema.

Agora, para ser capaz de colocar vértices em um HashMap, o método hashCode() deve retornar resultados consistentes com equals(). Ele atualmente faz isso, mas provavelmente baseia seu valor de retorno sobre os campos do Point3f, e, portanto, vai dar colisões de hash para diferentes objetos Vertex com as mesmas coordenadas.

Portanto, eu gostaria de basear o hashCode() no endereço do objeto, em vez de computação que nos campos do Vertex. Eu sei que a classe Object faz isso, mas eu não posso chamar seu método hashCode() porque Point3f substituirá.

Então, na verdade, a minha pergunta é dupla:

  • Devo até querer tal equals() uma rasa?
  • Se sim, então, como faço para obter o endereço do objeto para calcular o código hash de?

Edit: Eu só pensei em algo ... eu poderia gerar um valor aleatório int na criação do objeto, e usar isso para o código de hash. Essa é uma boa ideia? Por que (não)?

Foi útil?

Solução

De qualquer uso System.identityHashCode () ou usar um IdentityHashMap.

Outras dicas

System.identityHashCode() retorna o mesmo código hash para o objeto dado como seria devolvido pela hashCode() método padrão, com ou sem classe do objeto dado substituições hashCode().

Você usar um delegado, embora esta resposta é provavelmente melhor.


class Vertex extends Point3f{
   private final Object equalsDelegate = new Object();
   public boolean equals(Object vertex){
      if(vertex instanceof Vertex){
         return this.equalsDelegate.equals(((Vertex)vertex).equalsDelegate);
      }
      else{
         return super.equals(vertex);
      }
   }
   public int hashCode(){
      return this.equalsDelegate.hashCode();
   }
}

Apenas FYI, o seu método equals não viola o contrato (para o contrato do objeto base que é) é igual ... que é basicamente o método é igual para o método base objeto, então se você quiser identidade é igual em vez do Vertex é igual , que é muito bem.

Como para o código de hash, você realmente não precisa mudá-lo, embora a resposta aceita é uma opção boa e será muito mais eficiente se a sua tabela hash contém uma grande quantidade de chaves de vértice que têm os mesmos valores.

A razão que você não precisa mudá-lo é porque ele é completamente bem que o código de hash irá devolver o mesmo valor para objetos que equivale retorna falso ... é mesmo um código hash válido apenas para retornar 0 toda a tempo, por exemplo, CADA. Se isto é eficiente para tabelas de hash é uma questão completamente diferente ... você vai ter um monte mais colisões se um monte de seus objetos têm o código mesmo hash (que pode ser o caso se você deixou código hash sozinho e tinha um monte de vértices com os mesmos valores).

Por favor, não aceitar isso como a resposta embora, é claro (o que você escolheu é muito mais prático), eu só queria te dar um pouco mais informações básicas sobre códigos de hash e iguais; -)

Por que você quer para substituir hashCode () em primeiro lugar? Você gostaria de fazê-lo se você quer trabalhar com alguma outra definição de igualdade. Por exemplo

public class A { int id;

boolean equals (A outra) {return other.id == id} public int hashCode () {return id;}

} onde você quer ser claro que, se do id são os mesmos, então os objetos são o mesmo, e você substituir hashcode para que você não pode fazer isso:

= HashSet hash de novo HashSet (); hash.add (novo Um (1)); hash.add (novo Um (1)); e ganhe 2 idênticos (do ponto de vista da sua definição de igualdade) de um. O comportamento correto seria, então, que você só tem um objeto no hash, a segunda gravação iria substituir.

Uma vez que você não está usando iguais como uma comparação lógica, mas uma agressão física (ou seja, é o mesmo objeto), a única maneira que você vai garantir que o hashcode irá retornar um valor único, é implementar uma variação do seu próprio sugestão. Em vez de gerar um número aleatório, usar UUID para gerar um único valor real para cada objecto.

O System.identityHashCode () irá funcionar, mais parte do tempo, mas não é garantido que o Object.hashCode () é não garantida para retornar um único valor para cada objeto. Eu vi o caso marginal acontecer, e ele provavelmente irá ser dependente da implementação VM, o que não é algo que você vai querer o seu código ser dependente.

Trecho do javadocs para Object.hashCode (): Tanto quanto for razoavelmente prático, o método hashCode definido pela classe Object não retornar inteiros distintos para objetos distintos. (Isto é tipicamente implementado pela conversão do endereço interno do objeto em um número inteiro, mas esta técnica de implementação não é exigido pela linguagem de programação Java ™.)

o problema desta endereços, é o caso de ter dois objectos pontuais separadas substituam um ao outro quando inserido no hashmap porque ambos têm o mesmo hash. Como não há iguais lógicas, com a substituição acompanha de hashCode (), o método identityHashCode pode realmente causar este cenário ocorrer. Quando o caso lógica só iria substituir entradas de hash para o mesmo ponto lógico, usando o sistema baseado em hash pode causar a ocorrer com quaisquer dois objetos, a igualdade (e mesmo classe) não é mais um fator.

O hashCode () é herdado do objeto e funciona exatamente como você pretende (no nível do objeto, não coordenar-nível). Não deve haver nenhuma necessidade de mudá-lo.

Como para a sua iguais-método, não há nenhuma razão para sequer usá-lo, desde que você pode apenas fazer obj1 == obj2 em seu código em vez de usar iguais, uma vez que é feito para triagem e semelhantes, coordenadas onde comparando faz muito mais sentido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top