java - sirve - Naturaleza transitiva del método equals
metodo hash java (4)
El contrato para el método equals(object)
especifica 4 propiedades a seguir: Reflexivo, Simétrico, Transitivo y Consistente. Si bien entiendo el peligro de no seguir Reflexivo, Simétrico y Consistente, y definitivamente puedo estar de acuerdo en que es bueno seguir transitivo, me preguntaba qué daño causaría si viola la propiedad Transitiva.
Específicamente, ¿cuál de la biblioteca Java (o varias bibliotecas de terceros) necesita la dependencia de que los equals
sean transitivos para que funcionen correctamente? Según entiendo, el marco de Colecciones funcionará si las otras 3 propiedades están bien implementadas.
Considere el Objeto a == b == c con a! = C (igualdad no transitiva)
El primer problema sería el contrato hashcode () que requiere que los hashcodes sean iguales si los objetos son iguales. Y podrá agregar ayc al mismo conjunto; esto puede ocasionar problemas sutiles en lugares inesperados.
Por el momento no conozco una API de Java que tenga problemas con la ausencia de transitividad. (Todavía estoy reflexionando para un ejemplo).
Pero independientemente de eso, se requiere transitividad para la igualdad porque esa es la definición matemática algebraica de la relación de igualdad. http://en.wikipedia.org/wiki/Equality_(mathematics)
Si la transitividad no está presente, el método no debe llamarse igual porque sería engañoso teniendo en cuenta la expectativa que uno tiene al escuchar / leer "igualdad". Esto contradiría el principio de menos asombro. http://en.wikipedia.org/wiki/Principle_of_least_astonishment
[EDITAR]
Lo interesante de esto es que hablando estrictamente matemáticamente, la "igualdad" definida por el método java equals no es una igualdad, sino más bien la relación de equivalencia más general http://en.wikipedia.org/wiki/Equivalence_relation porque también se pueden usar diferentes objetos. "igual" según java, contradiciendo así la propiedad antisimetría requerida para una verdadera igualdad.
Conclusión:
.equals en Java es una relación de equivalencia (que aún requiere transitividad)
== en Java es una relación de igualdad (o identidad)
Suponga tres objetos a, b, c con
a == a, b == b, c == c (reflexive)
a == b, b == a
b == c, c == b
a != c, c != a
(Pseudocódigo, x == y
significa x.equals(y)
).
Ahora, agreguemos los objetos a un conjunto:
Set s = new HashSet(); // Set implementation doesn''t matter
s.add(b); // s = [b]
s.add(a); // s doesn''t change, because a == b
s.add(c); // s doesn''t change, because c == b
Por el contrario, si tuviéramos que agregarlos en un orden diferente:
Set s = new HashSet();
s.add(a); // s = [a]
s.add(b); // s doesn''t change, because b == a
s.add(c); // s = [a,c], because c != a
Eso es claramente contrario a la intuición y no coincide con el comportamiento que cabría esperar de un conjunto. Por ejemplo, significaría que la unión de dos conjuntos (es decir, el estado de s después de s.addAll(someOtherSet)
) podría depender de la implementación (orden de los elementos) de algún otro conjunto.
Integer a = new Integer(1);
Integer b = new Integer(1);
a == 1
es verdadero, b == 1
es verdadero pero, a == b
no es verdadero.