我在假设,如果你有一个包含一个Java集<>内(或在地图<>对于这个问题的关键)的对象,所使用的任何字段,以确定身份或关系(通过正确hashCode()
, equals()
compareTo()
等)不能在没有对采集造成不确定的行为进行操作改变了吗? (编辑:在提到这个问题,其他 )
(换句话说,这些领域要么是不可变的,或者如果您需要将对象从集合中删除,然后改,然后重新插入。)
我要求的原因是,我正在读Hibernate标注参考指南 ,它有一个例子,其中有一个HashSet<Toy>
但Toy
类有字段name
和serial
是可变的,并且在也用于hashCode()
计算。 ..红旗在我的头上去了,我只是想确认我的理解它的含义。
适用于Javadoc Set
说
注意:如果使用可变对象作为一组元素大,一定要小心。 如果一个对象的值以影响equals比较而对象是在该组的元素的方式改变一组的行为没有被指定。 这种禁止的特殊情况是,它是不允许的一组以自身作为一个元素。
这只是意味着你可以在一组使用可变对象,甚至改变他们。 你刚才应该确保更改不会影响的方式Set
找到的项目。 对于HashSet
,这将需要不改变用于计算领域hashCode()
这是正确的,它可能会导致一些问题,定位映射条目。 官方的行为是不确定的,所以如果你把它添加到HashSet或HashMap中的关键,你不应该改变它。
是的,这会造成不好的事情发生。
// 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
在一个HashSet / HashMap中,你可能会变异包含的对象来改变的结果compareTo()
操作-相对比较不用于定位的对象。 但它会是一个TreeSet / TreeMap的内部致命的。
您也可以发生变异是一个IdentityHashMap中的对象 - 无非对象标识等用于定位的内容。
即使你可以做这些事情与这些资格,他们使你的代码更加脆弱。 如果有人想在以后改变到一个TreeSet,或可变的字段添加到的hashCode /平等的测试?