java eclipse equals

java - ¿Qué parte del contrato general es igual a() igual a mi igual?



eclipse equals (3)

Soy bastante nuevo en java y solo estoy tratando de entender @Override el modo @Override of the equals() y hashcode() .
Sé que para que el método equals sea correcto, debe ser:

  1. Reflexivo: a.equals(a)
  2. Simétrico: a.equals(b) luego b.equals(a)
  3. Transitivo: a.equals(b) && b.equals(c) Luego a.equals(c)
  4. No nulo ! a.equals(null) ! a.equals(null)

Estoy luchando para identificar cuál de las propiedades anteriores soy y no estoy satisfaciendo cuando escribo mi overide del método equals.

Soy consciente de que Eclipse puede generarlos para mí, sin embargo, como todavía no he recibido el concepto por completo, escribirlo me ayuda a aprender.

He escrito lo que creo que es la forma correcta de hacerlo, pero cuando verifico con la versión generada por Eclipse, parece que "faltan" algunos aspectos.

Ejemplo:

public class People { private Name first; //Invariants --> !Null, !=last private Name last; // !Null, !=first private int age; // !Null, ! <=0 ... }

Lo que escribí:

public boolean equals(Object obj){ if (obj == null){ return false; } if (!(obj instanceof People)){ return false; } People other = (People) obj; if (this.age != other.age){ return false; } if (! this.first.equals(other.first)){ return false; } if (! this.last.equals(other.last)){ return false; } return true; }

eclipse vs generado

public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; People other = (People) obj; if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false; if (age != other.age) return false; if (last == null) { if (other.last != null) return false; } else if (!last.equals(other.last)) return false; return true; }

Estoy perdido:

  • if (this == obj) return true;

  • if (getClass() != obj.getClass()) return false;

  • Y para cada variable:

    if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false;

No estoy seguro de qué es getClass() y mi implementación es incorrecta.


No creo que su implementación sea incorrecta, pero algunas notas:

if (this == obj) return true;

Es una optimización del rendimiento, prueba directamente la igualdad de referencia y las pruebas de cortocircuito donde a es a .

if (getClass() != obj.getClass()) return false;

Es similar a su instanceof llamada, optimiza lejos un cheque nulo. Las otras llamadas parecen ser cheques nulos.


No necesitas escribir

if (obj == null){ return false; } if (!(obj instanceof People)){ return false; }

Porque null siempre da false en el instanceof cheques. Así que estas líneas se pueden simplificar a solo

if (!(obj instanceof People)){ return false; }

En cuanto a su pregunta principal de si su método cumple con los requisitos para un método equals() , estrictamente hablando, la respuesta es no, o al menos es potencialmente poco fiable. Esto se debe a que sería posible extender la clase de la siguiente manera

public class SpecialPeople extends People { // code omitted @Override public boolean equals(Object object) { if (object == null || object.getClass() != getClass()) return false; SpecialPeople other = (SpecialPeople) object; return other.getAge() == getAge() && other.getFirst().equals(getFirst()) && other.getLast().equals(getLast()); }

Ahora suponga que a es una instancia de People y b es una instancia de SpecialPeople . Supongamos también que b tienen el mismo nombre y edad. Entonces

a.equals(b) == true // instanceof check succeeds b.equals(a) == false // getClass() check fails

Por lo tanto equals() no es simétrico! Por esta razón, si está utilizando instanceof lugar de getClass() en equals() , probablemente debería hacer que el método equals() final o la clase final .


Primera pieza de código:

if (this == obj) return true;

Esto mejora el rendimiento en caso de que compares la referencia del objeto contra sí mismo. Ejemplo: a.equals(a); .

Segunda pieza de código:

if (getClass() != obj.getClass()) return false;

Esto compara si la clase de la referencia que se está comparando es la misma clase de this . La diferencia entre usar este enfoque y instanceof es que es más restrictivo cuando se compara con una subclase. Ejemplo:

public class Foo { } public class Bar extends Foo { } //... Foo foo = new Bar(); System.out.println(foo instanceof Bar); //prints true System.out.println(foo instanceof Foo); //prints true Foo foo2 = new Foo(); System.out.println(foo.getClass() == foo2.getClass()); //prints false

¿Cuál debería elegir? No hay un enfoque bueno o malo, dependerá de su diseño deseado.

Tercera pieza de código:

if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false; //For each variable.

Esto es simplemente una comprobación nula para cada campo de referencia de objeto en la clase. Tenga en cuenta que si this.first es null , hacer this.first.equals(...) generará una NullPointerException .