繁体   English   中英

Java集中对象的可变字段

[英]mutable fields for objects in a Java Set

假设你有一个包含在Java Set <>中的对象(或者作为Map <>中的一个关键字),我是否正确,用于确定身份或关系的任何字段(通过hashCode()equals()compareTo()等)如果不对集合上的操作造成未指定的行为,则无法更改? (编辑:在其他问题中提到)

(换句话说,这些字段应该是不可变的,或者您应该要求从集合中删除对象,然后更改,然后重新插入。)

我问的原因是我正在阅读Hibernate Annotations参考指南 ,它有一个示例,其中有一个HashSet<Toy>但是Toy类具有可变的字段nameserial ,并且也用于hashCode()计算。我的头脑里出现了一面红旗,我只想确保理解它的含义。

Set的javadoc说

注意:如果将可变对象用作set元素,则必须非常小心。 如果在对象是集合中的元素的同时以影响等于比较的方式更改对象的值,则不指定集合的​​行为。 这种禁令的一个特例是,不允许集合将自身作为一个要素包含在内。

这只是意味着您可以在集合中使用可变对象,甚至可以更改它们。 您应该确保更改不会影响Set找到项目的方式。 对于HashSet ,这不需要更改用于计算hashCode()的字段。

这是正确的,它可能会导致一些问题,找到地图条目。 官方的行为是未定义的,因此如果将其添加到哈希集或作为哈希映射中的键,则不应更改它。

是的,这会导致不好的事情发生。

// 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 / equality测试,该怎么办?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM