【问题标题】:Would a Java HashSet<String>'s contains() method test equality of the strings or object identity?Java HashSet<String> 的 contains() 方法会测试字符串或对象标识的相等性吗?
【发布时间】:2012-02-16 13:14:16
【问题描述】:

假设我有这段 Java 代码:

HashSet<String> wordSet = new HashSet<String>();
String a = "hello";
String b = "hello";
wordSet.add(a);

wordSet.contains(b); 会返回true 还是false?据我了解,ab 指的是不同的对象,即使它们的值相同。所以contains() 应该返回false。但是,当我运行此代码时,它会返回 true只要b 包含值"hello",无论字符串对象b 来自何处,它是否总是返回true?我是否总是保证这一点?如果不是,我什么时候不能保证这一点?如果我想对字符串以外的对象做类似的事情呢?

【问题讨论】:

    标签: java string reference hashset


    【解决方案1】:

    它使用equals() 来比较数据。以下来自javadoc for Set

    如果集合不包含任何元素,则将指定元素 e 添加到该集合中 元素 e2 使得 (e==null ? e2==null : e.equals(e2))。

    String 的equals() 方法进行逐个字符的比较。来自javadoc for String

    当且仅当参数不为 null 并且是一个字符串对象,该对象表示与此对象相同的字符序列时,结果才为真

    【讨论】:

      【解决方案2】:

      实际上,HashSet两者都没有

      它的实现使用了HashMap,下面是判断集合contains()的相关代码(其实是在HashMap的getEntry()方法里面):

      if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
      

      其中:

      • 要求哈希值相等,并且
      • 要求要么对象相等或equals()返回真

      答案是“是”:wordSet.contains(b) 将始终返回 true

      【讨论】:

      • OP 询问了HashSet&lt;String&gt;String 类的hashCode 方法为equals 为真的两个字符串返回相等的值。如果String 类的equals 方法的参数与调用它的对象相同,则该方法返回true。所以你引用的条件在逻辑上等同于equals()
      【解决方案3】:

      实际上,a 和 b 都指向同一个对象,因为 Java 中的字符串字面量是自动实习的。

      【讨论】:

      • ...这就是为什么他/她说'只要 b 包含值“hello”,无论字符串对象 b 来自何处,它都会返回 true 吗?'
      • From what I understand, a and b refer to different objects even though their values are the same - 我很确定他不是这么想的。
      • 是的,对不起,你是对的。无论如何,他/她问的问题是 HashSet 是使用相等还是标识;只是他/她的例子有点缺陷。
      • 那如果是自动实习的,为什么还有intern()方法呢?
      • 因为它们只有在以文字开始时才会自动被实习。但是,如果您从其他地方获取字符串(例如,您从文件中读取它,或者从子字符串构建它),那么实习将改变它的身份。
      【解决方案4】:

      两件事:

      1. 除非调用 equals() 方法来确定相等性,否则集合将毫无用处。 wordset.contains(b) 将返回 true,因为 a.equals(b) == true。

      2. 您不能完全确定 a 和 b 指向不同的对象。查看 String.intern() 了解更多详情。

      【讨论】:

        【解决方案5】:

        最终contains 将检查equals 方法而不是其对象ID 验证包含方法。因此 equals 方法将被调用 contains 调用。 这是contains方法的调用结构。

        private transient HashMap<E,Object> map;
            public boolean contains(Object o) {
            return map.containsKey(o);
            }
        
        
            public boolean containsKey(Object key) {
                return getEntry(key) != null;
            }
        
        
            final Entry<K,V> getEntry(Object key) {
                int hash = (key == null) ? 0 : hash(key.hashCode());
                for (Entry<K,V> e = table[indexFor(hash, table.length)];
                     e != null;
                     e = e.next) {
                    Object k;
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                }
                return null;
            }
        

        【讨论】:

        • HashSet 也一样?
        • 是的,对于HashSetequals 方法也会为 contains 调用
        【解决方案6】:

        平等。在您的示例中,contains() 返回 true,因为 HashSet 检查了a.equals( b )

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-06
          • 2017-10-29
          • 2015-01-18
          • 2012-06-29
          相关资源
          最近更新 更多