【问题标题】:What happens when I add duplicate element into HashSet? Is old element overwritten or not?当我将重复元素添加到 HashSet 时会发生什么?旧元素是否被覆盖?
【发布时间】:2021-01-18 06:41:44
【问题描述】:

假设我想在HashSet 中添加重复元素。我们知道这是不允许的。所以我遇到了 2 个,比如说 theories

link 的“属性,编号 2”下,它说:

HashSet 不允许重复元素。如果您尝试插入 重复元素,旧元素将被覆盖

但是当我在 IDE 中检查提供给我的文档时,在方法 add() 中,它指出:

* If this set already contains the element, the call leaves the set
* unchanged and returns {@code false}.

那么它是覆盖(替换)旧元素还是保持集合不变并返回 false? :) 我是不是被他们说得完全相反?

【问题讨论】:

  • IDE 取自官方文档。另一个只是一些随机站点。你更愿意相信谁?
  • IDE :) 但是制作那个网站的人怎么会犯这么大的错误呢?
  • 你不可能是那个互联网新手 :-)
  • @Stefan 因为出于所有意图和目的,结果都是一样的 :) 另外,tevemadar 所说的:P
  • @tevemadar 哈哈是真的.. 但问题是那些“随机”网站有时会对某些概念做出“更漂亮”的解释。作为初学者,我有时很难理解官方文档

标签: java duplicates add hashset


【解决方案1】:

任何理论都可以通过查看源代码来验证。

例如,对于 JDK 8,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&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;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;
    }

这里mapHashMap的一个实例,所以我们应该看看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;
            }

【讨论】:

  • 查阅官方javadoc比看源码要好得多。源代码可以从一个 Java 版本更改(并且已经更改)到下一个版本,但 javadoc 不仅仅是文档,它是一个 contract,它永远指定有保证的行为,无论内部实现如何.
【解决方案2】:

执行下面的程序,你会看到重复的元素是不允许的:

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);
    }

}

【讨论】:

    【解决方案3】:

    IDE 正在显示Set.add 方法的官方规范(javadocs)的摘录。

    IDE 是正确的。相信官方文档,而不是一些“漂亮”的网站。


    但是,制作那个网站的人怎么会犯这么大的错误呢?

    永远记住,像您发现的网站这样的网站的主要动机是从您的网页浏览量中赚钱。他们通常更关注“搜索引擎优化”,而不是材料的质量。


    但问题是那些“随机”网站有时会对某些概念做出“更漂亮”的解释。作为初学者,我有时很难理解官方文档。

    那么哪个更可取?一些容易阅读但错误的东西?还是准确的?

    在这种情况下,你不能说官方文档很难理解。官方文档中的文字和第三方网站的文字之间的矛盾,你自己也看出来了。

    我的建议是我们始终尝试首先阅读官方 javadocs,并始终相信它比任何其他来源... 包括 StackOverflow 答案!唯一更确定的事情 1是OpenJDK源码。


    1 - 甚至这也是有争议的。一方面,代码决定了实际发生的情况。另一方面,代码可能会从一个版本更改为另一个版本。因此,依赖 javadocs 中未指定的行为可能会导致可移植性问题。

    【讨论】:

      猜你喜欢
      • 2021-09-22
      • 2020-04-22
      • 2015-08-16
      • 1970-01-01
      • 2019-01-08
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      相关资源
      最近更新 更多