2012-09-02 19 views
10

Cuando leo un libro de Java, el autor ha dicho que, al diseñar una clase, generalmente no es seguro usar equals() con herencia. Por ejemplo:¿Por qué no debería usar iguales con la herencia?

public final class Date { 
    public boolean equals(Object o) { 
     // some code here 
    } 
} 

En la clase anterior, hay que poner final, por lo que otra clase no puede heredar de esto. Y mi pregunta es, ¿por qué no es seguro cuando permite que otra clase herede de esto?

+0

'Comparable' especifica' compareTo', no 'equals', por cierto. – oldrinb

+0

Oh. gracias :) He editado: D – hqt

+0

¿Cuál es el nombre del libro? –

Respuesta

19

Porque es difícil (¿imposible?) Hacerlo bien, especialmente el symmetric property.

Digamos que tiene la clase Vehicle y la clase Car extends Vehicle. Vehicle.equals() produce true si el argumento es también Vehicle y tiene el mismo peso. Si se desea implementar Car.equals() debe dió true sólo si el argumento es también un coche, y con excepción de peso, sino que también debe comparar realizar, motor, etc.

Ahora imagine el siguiente código:

Vehicle tank = new Vehicle(); 
Vehicle bus = new Car(); 
tank.equals(bus); //can be true 
bus.equals(tank); //false 

La primera comparación podría arrojar true si coinciden el tanque y el autobús tienen el mismo peso. Pero como el tanque no es un automóvil, compararlo con un automóvil siempre dará como resultado false.

usted tiene pocas soluciones temporales:

  • estricto: dos objetos son iguales si y sólo si tienen exactamente el mismo tipo (y todas las propiedades son iguales). Esto es malo, p. cuando subclases apenas para agregar algún comportamiento o decorar la clase original. Algunos frameworks también están subclasificando tus clases sin que notes (Hibernate, Spring AOP con proxies CGLIB ...)

  • loose: dos objetos son iguales si sus tipos son "compatibles" y tienen los mismos contenidos (semánticamente). P.ej. dos conjuntos son iguales si contienen los mismos elementos, no importa que uno sea HashSet y el otro sea TreeSet (gracias @veer para señalar eso).

    Esto puede ser engañoso. Tome dos LinkedHashSet s (donde el orden de inserción es importante como parte del contrato). Sin embargo, desde equals() sólo toma cruda Set contrato en cuenta, los rendimientos de comparación true incluso para obviamente diferentes objetos:

    Set<Integer> s1 = new LinkedHashSet<Integer>(Arrays.asList(1, 2, 3)); 
    Set<Integer> s2 = new LinkedHashSet<Integer>(Arrays.asList(3, 2, 1)); 
    System.out.println(s1.equals(s2)); 
    

Ver también

+1

No * imposible *; ver p. ['Set.equals'] (http://docs.oracle.com/javase/7/docs/api/java/util/Set.html#equals (java.lang.Object)) – oldrinb

+0

@veer: Actualicé mi respuesta, gracias –

+0

@TomaszNurkiewicz como su enlace, si usamos 'if (this.getClass()! = Tank.getClass()) {return false;}' o 'if (this.getClass()! = Tank.getClass()) {return false;} ', el problema se resolverá. ¿Puedes decirme más sobre este caso? – hqt

8

Martin Odersky (la chico detrás de los genéricos en Java y la base de código original para el actual javac) tiene un buen capítulo en su libro Programación en Scala que trata este problema. Sugiere que agregar un método canEqual puede solucionar el problema de igualdad/herencia.Puede leer la discusión en la primera edición de su libro, que está disponible en línea:

Chapter 28 of Programming in Scala, First Edition: Object Equality

El libro es, por supuesto, en referencia a Scala, pero las mismas ideas se aplican a los clásicos de Java. El código fuente de la muestra no debería ser demasiado difícil de entender para alguien que proviene de un fondo de Java.

Editar:

Parece que Odersky publicó un artículo en el mismo concepto en Java en 2009, y está disponible en la misma página web:

How to Write an Equality Method in Java

Realmente no piense que tratar de resumir el artículo en esta respuesta le haría justicia. Cubre el tema de la igualdad de objetos en profundidad, desde errores comunes en implementaciones de igualdad hasta una discusión completa de Java equals como una relación de equivalencia. Realmente deberías solo leerlo.

Cuestiones relacionadas