当我将重复元素添加到 HashSet 时会发生什么?旧元素是否被覆盖?
What happens when I add duplicate element into HashSet? Is old element overwritten or not?
假设我想在 HashSet
中添加重复元素。我们知道这是不允许的。所以我遇到了 2,比方说 理论。
在这个 link 的 'PROPERTIES, number 2' 下,它说:
HashSet does not allow duplicate elements. If you try to insert a
duplicate element, older element will be overwritten
但是当我检查 IDE 中提供给我的文档时,在方法 add()
中,它指出:
* If this set already contains the element, the call leaves the set
* unchanged and returns {@code false}.
那么它是覆盖(替换)旧元素还是保持集合不变并且returns false? :) 我是不是很讨厌他们说的恰恰相反?
任何理论都可以通过查看源代码来验证。
例如对于JDK8,HashSet::add
实现如下:
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
这里map
是HashMap
的一个实例,所以我们应该看看HashMap::put
:
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
和 putVal
的实现包含此代码:
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
执行下面的程序,你会看到不允许重复的元素:
import java.util.HashSet;
public class Test {
public static class Dummy{
String s1;
String s2;
public Dummy(String s1, String s2) {
super();
this.s1 = s1;
this.s2 = s2;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((s1 == null) ? 0 : s1.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dummy other = (Dummy) obj;
if (s1 == null) {
if (other.s1 != null)
return false;
} else if (!s1.equals(other.s1))
return false;
return true;
}
@Override
public String toString() {
return "Dummy [s1=" + s1 + ", s2=" + s2 + "]";
}
}
public static void main(String[] args) {
HashSet<Object>hashSet =new HashSet<>();
Object o1 = new Dummy("a","b");
Object o2 = new Dummy("a","c");
System.out.println(o1.equals(o2));
hashSet.add(o1);
System.out.println(hashSet);
hashSet.add(o2);
System.out.println(hashSet);
}
}
IDE 正在显示 Set.add
方法的官方规范(javadocs)的摘录。
IDE 是正确的。相信官方文档,而不是一些“漂亮”的网站。
But how could people that made that site make such a big mistake then?
永远记住,像您发现的网站这样的网站的主要动机是通过您的页面浏览量赚钱。他们通常更关注“搜索引擎优化”,而不是 material.
But the problem is those "random" sites sometimes make 'prettier' explanation of some concepts. Official docs are sometimes too hard to follow for me as a beginner.
那么哪个更好?一些容易阅读但错误的东西?或者准确的东西?
在这种情况下,你不能说官方文档难懂。您自己能够看到官方文档和 3rd-party 网站上的文本之间的矛盾。
我建议我们始终尝试先阅读官方 javadoc,并始终相信它优于任何其他来源...包括 Whosebug 答案!唯一的事情是更权威1 是 OpenJDK 源代码。
1 - 即使这样也值得商榷。一方面,代码决定了实际发生了什么。另一方面,代码可能会从一个版本更改为另一个版本。因此,依赖 javadoc 中未 指定 的行为可能会导致可移植性问题。
假设我想在 HashSet
中添加重复元素。我们知道这是不允许的。所以我遇到了 2,比方说 理论。
在这个 link 的 'PROPERTIES, number 2' 下,它说:
HashSet does not allow duplicate elements. If you try to insert a duplicate element, older element will be overwritten
但是当我检查 IDE 中提供给我的文档时,在方法 add()
中,它指出:
* If this set already contains the element, the call leaves the set * unchanged and returns {@code false}.
那么它是覆盖(替换)旧元素还是保持集合不变并且returns false? :) 我是不是很讨厌他们说的恰恰相反?
任何理论都可以通过查看源代码来验证。
例如对于JDK8,HashSet::add
实现如下:
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
这里map
是HashMap
的一个实例,所以我们应该看看HashMap::put
:
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
和 putVal
的实现包含此代码:
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
执行下面的程序,你会看到不允许重复的元素:
import java.util.HashSet;
public class Test {
public static class Dummy{
String s1;
String s2;
public Dummy(String s1, String s2) {
super();
this.s1 = s1;
this.s2 = s2;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((s1 == null) ? 0 : s1.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dummy other = (Dummy) obj;
if (s1 == null) {
if (other.s1 != null)
return false;
} else if (!s1.equals(other.s1))
return false;
return true;
}
@Override
public String toString() {
return "Dummy [s1=" + s1 + ", s2=" + s2 + "]";
}
}
public static void main(String[] args) {
HashSet<Object>hashSet =new HashSet<>();
Object o1 = new Dummy("a","b");
Object o2 = new Dummy("a","c");
System.out.println(o1.equals(o2));
hashSet.add(o1);
System.out.println(hashSet);
hashSet.add(o2);
System.out.println(hashSet);
}
}
IDE 正在显示 Set.add
方法的官方规范(javadocs)的摘录。
IDE 是正确的。相信官方文档,而不是一些“漂亮”的网站。
But how could people that made that site make such a big mistake then?
永远记住,像您发现的网站这样的网站的主要动机是通过您的页面浏览量赚钱。他们通常更关注“搜索引擎优化”,而不是 material.
But the problem is those "random" sites sometimes make 'prettier' explanation of some concepts. Official docs are sometimes too hard to follow for me as a beginner.
那么哪个更好?一些容易阅读但错误的东西?或者准确的东西?
在这种情况下,你不能说官方文档难懂。您自己能够看到官方文档和 3rd-party 网站上的文本之间的矛盾。
我建议我们始终尝试先阅读官方 javadoc,并始终相信它优于任何其他来源...包括 Whosebug 答案!唯一的事情是更权威1 是 OpenJDK 源代码。
1 - 即使这样也值得商榷。一方面,代码决定了实际发生了什么。另一方面,代码可能会从一个版本更改为另一个版本。因此,依赖 javadoc 中未 指定 的行为可能会导致可移植性问题。