mutable campos de objetos en un Conjunto de Java
-
21-08-2019 - |
Pregunta
Estoy en lo cierto al suponer que si tienes un objeto que se encuentra dentro de un Conjunto de Java<> (o como una clave en un Mapa<> para el caso), los campos que se utilizan para determinar la identidad o relación (a través de hashCode()
, equals()
, compareTo()
etc.) no se puede cambiar sin causar sin especificar el comportamiento de las operaciones en la colección?(edición:como se menciona en el esta otra pregunta)
(En otras palabras, estos campos deben ser inmutables, o usted necesita el objeto para ser eliminado de la colección, a continuación, cambiar, a continuación, vuelva a insertar.)
La razón que pido es que me estaba leyendo el Hibernate annotations guía de referencia y él tiene un ejemplo donde hay un HashSet<Toy>
pero el Toy
la clase tiene campos name
y serial
que son mutables y también son utilizados en la hashCode()
cálculo de...una bandera roja se apagó en mi cabeza y yo sólo quería asegurarme de que he entendido las implicaciones de la misma.
Solución
El Javadoc para Set
dice
Nota: El gran cuidado debe ejercerse si objetos mutables se utilizan como conjunto elementos. El comportamiento de un conjunto no es especificado si el valor de un objeto es cambiado de una manera que afecta es igual a comparaciones mientras que el objeto es un elemento en el conjunto. Un caso especial de esta prohibición es que no es permisible para un conjunto de contener a sí mismo como un elemento.
Esto simplemente significa que puede utilizar objetos mutables en un conjunto, e incluso cambiarlos. Usted sólo debe asegurarse de que el cambio no afecta a la forma en que el HashSet
encuentra los artículos. Para hashCode()
, que requeriría no cambiar los campos que se utilizan para el cálculo de <=>.
Otros consejos
Eso es correcto, puede causar algunos problemas para localizar la entrada del mapa. Oficialmente, el comportamiento no está definido, por lo que si se agrega a una hashset o como una llave en una HashMap, no debe ser el cambio de la misma.
Sí, eso hará que sucedan cosas malas.
// Given that the Toy class has a mutable field called 'name' which is used
// in equals() and hashCode():
Set<Toy> toys = new HashSet<Toy>();
Toy toy = new Toy("Fire engine", ToyType.WHEELED_VEHICLE, Color.RED);
toys.add(toy);
System.out.println(toys.contains(toy)); // true
toy.setName("Fast truck");
System.out.println(toys.contains(toy)); // false
En un HashSet / HashMap, que podría mutar un objeto contenido para cambiar los resultados de la operación compareTo()
- comparación relativa no se utiliza para localizar objetos. Pero sería fatal dentro de un TreeSet / TreeMap.
También puede mutar objetos que se encuentran dentro de un IdentityHashMap - nada que no sea la identidad del objeto se utiliza para localizar contenidos.
A pesar de que usted puede hacer estas cosas con estos requisitos, hacen que el código sea más frágil. ¿Y si alguien quiere cambiar a un TreeSet más tarde, o añadir ese campo mutable a la prueba hashCode / igualdad?