回答
大多数时候一组应该只包含immutables。
从the JavaDoc of the Set interface:
注意:如果使用可变对象作为一组元素大,一定要小心。没有指定集合的行为如果对象的值以影响等于比较的方式更改,而对象是集合中的元素,则该对象的值会发生更改。这种禁令的一个特例是,一个集合不允许自己作为一个元素。
强调我的。
如果您能够在不影响equals()
的情况下修改元素,我会强烈重新考虑您的等值实现是否正确。
如果程序员编写调用它的代码并不会让任何程序员惊讶,那么'equals()'的实现就是_correct_。 (这并不意外,任何程序员都会在Set中使用你的类的成员。)如果你是唯一一个会使用你的类编写代码的人,那么你的意见是唯一重要的。另一方面,如果您打算让您的代码被其他人重新使用,那么您可能想要更加认真地考虑其他人期望“equals()”的含义。 –
我不同意。我相信任何'equals'的实现都应该比较每个字段。这是将被普遍理解的* only *实现。如果你想比较一个对象字段的子集,你应该添加另一个明智的命名方法:'isSamePlaceAs()','isSameSizeAs()'等。 – Michael
由于您可以通过修改里面的可变元素来打破Set
,所以不可变的肯定是首选。
一个问题,举例来说,就是如果你添加一个A a
一组,然后在改变其哈希码,有一个机会,set.contains(a)
将返回错误的方式发生变异a
。
简单的例子:
public static void main(String[] args) {
Set<A> set = new HashSet<>();
A a = new A(1);
set.add(a);
System.out.println(set.contains(a)); //true
a.i = 2;
System.out.println(set.contains(a)); //false
}
static class A {
int i;
public A(int i) { this.i = i; }
@Override public int hashCode() { return i; }
}
一个假设你的例子假定一个相应的'equals'实现,即使你没有显示它。 –
@LewBloch这个例子不需要工作,但是一般情况下你也可以重写'equals'。 – assylias
如果'equals'方法返回错误的答案,那么'Set'如何找到该项目?是的,这个例子是必需的。请记住,哈希集合既使用'hashCode'也使用equals。如果它们不一致,代码就会中断。实际上,你声称破碎的代码是可以接受的。 –
它最有可能闻起来,因为如果一个字段被修改,也被用来计算hashCode,Set
打破。因此可以打破Set
。
相反,修改List
中的元素将永远不会破坏该列表。
简单的例子(截断并从assylias扩展回答)
public class Main {
public static void main(String[] args) {
Set<A> set = new HashSet<>();
List<A> list = new ArrayList<>();
A a = new A(1);
set.add(a);
list.add(a);
System.out.println(set.contains(a)); // true
System.out.println(list.contains(a)); // true
a.i = 2;
System.out.println(set.contains(a)); // false
System.out.println(list.contains(a)); // true
}
static class A {
int i;
public A(int i) {
this.i = i;
}
@Override
public int hashCode() {
return i;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof A)) {
return false;
}
A other = (A) obj;
if (i != other.i) {
return false;
}
return true;
}
}
}
假设你的例子假定你有相应的'equals'实现,即使你不要显示 –
谢谢Lew,固定。 – kerner1000
建议成语:'return i == other.i'。在'if'中使用'boolean'来确定'boolean'有点多余。 –
- 1. DOM元素可以包含一个包含空格的ID吗?
- 2. 我可以选择一个不包含其他元素的元素吗?
- 3. 变体数组可以包含0个元素吗?
- 4. MongoDB - 指定集合可能只包含一个文档
- 5. 断言集合“至少包含一个非空元素”
- 6. 为什么我的集合不包含多个元素? - python 2.7
- 7. Vue js错误:组件模板应该只包含一个根元素
- 8. LINQ:查询集合是否包含另一个集合中的任何元素
- 9. MYSQL:外键可以包含一个集合吗?
- 10. 类应该包含它自己的集合吗?
- 11. AggregateRoot应该包含其他AggregateRoot的集合吗?
- 12. 包含wxCheckBox元素的wxTreeCtrl。可能吗?
- 13. XSLT:XTSE0010:一个fo:block元素不能包含一个xsl:param元素
- 14. HMENU只包含子元素
- 15. 应该JSON Api属性元素包含嵌套对象吗?
- 16. 什么算法来找到包含至少一个元素的最小集合(每个集合包含至少一个元素)
- 17. 一个集合可以有列表作为其元素吗?
- 18. Android:创建一个包含可变元素的片段
- 19. 包含应该改变状态的图标的按钮元素
- 20. IOrderedEnumerable <T>是一个固有的不可变集合吗?我应该/可以屈服吗?
- 21. 有什么办法可以选择一个包含任何其他集合元素的集合?
- 22. api.raml应该包含整个API吗?
- 23. hibernate ehcache只发现一个集合中的一个元素
- 24. 包含元素和其他集合用于构造C++的集合的集合
- 25. java.lang.IndexOutOfBoundsException:集合不包含索引4处的元素
- 26. HQL:是另一个集合中的一个集合的元素吗?
- 27. 如何创建包含2个元素集合的实体?
- 28. 元素的发现数包含两个集合
- 29. XML元素可以同时包含文本和子元素吗?
- 30. jq:只选择一个包含元素A但不包含元素B的数组
它不只是闻。它打破了。 –
取决于哪些字段用于计算hashCode/equals以及哪些字段被修改。 – kerner1000