为什么我可以在HashMap中使用字符串作为键?

5
如果两个相同的字符串实际上不是相同的,那么我为什么可以在HashMap中使用字符串作为键,而不使用相同的String对象呢?
String s1 = "Test";
String s2 = "Test";

System.out.println(s1 == s2); // should be false
System.out.println(s1.equals(s2)); // should be true

HashMap<String, String> map = new HashMap();
map.put(s1, "foo");
System.out.println(map.get(s2)); // should be "foo"--but why?

HashMapString 对象有特殊的行为吗?如果没有,为什么两个“不同”的字符串可以用于将值放入哈希表中并从哈希表中获取值?


6
请注意,由于字符串内部化(string interning)的原因,s1 == s2 将为 true - Ted Hopp
那么为什么使用.equals()来比较String是标准做法呢? - Tom Marthenal
1
@Ted Hopp 因为常量池化,s1 == s2 将会是真的。 - user207421
@TomMarthenal:Ted 正在谈论你的特定情况;这并不适用于一般情况。 - SLaks
@Tom 因为可能存在具有相同值的不同 String 对象。使用其中一个 String 构造函数来强制创建新对象。但在你的示例中,你没有使用 String 构造函数,它很可能会打印两次 true。 - Fabian Barney
显示剩余3条评论
6个回答

14

HashMap通过调用equals()hashCode()方法来比较对象。
String重写这些方法以按值进行比较。


5

通常情况下,您可以使用字符串对象,因为HashMap使用equals()而不是==来测试键的相等性。


4
如果两个字符串相同但实际上不相等,那么它们在equals()方法下是相等的,而这是Map接口中指定用于测试相等性的技术。
System.out.println(s1 == s2); // should be false

但这并不是假的!由于编译器的常量池化,两者都引用同一个字符串。


2
HashMap 在内部比较键时,它使用的是 equals() 方法,而不是 ==。因此,如果已经重写了 equals() 方法(例如在 java.lang.String 中),则对象相等性就可以用于键匹配,而不需要引用相等性。

1
System.out.println(s1 == s2); // 应该为false 它并不应该。Java编译器可能会优化并将两个字符串指向相同的位置。
public class Test {

    public static void main(String... args) {
        String s1 = "abc";
        String s2 = "abc";

        System.out.println(s1 == s2);
    }

}

输出

javac Test.java
java Test
> true

错误,错误,错误。你可以用简单的代码轻松证明它。 - duffymo
2
根据“可能优化”,我认为你的意思是“必须优化”,假设Java编译器符合规范。http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.5 - yshavit
等一下 - 我误读了原文,我为这两个字符串调用了“new”。对不起。我再次投了票。我太匆忙了。 - duffymo

-2

我们应该先回到基础。

计算机科学基础:

== 比较内存地址(引用)

.equals 比较存储在内存地址中的值

Java 基础。整个 JVM 中只有一个字符串对象的副本。


3
你的回答里几乎每一行都存在微妙或明显的错误。 - SLaks
这些不是“计算机科学基础”。它们是Java基础。Java引用不一定是内存地址。如果使用new String(...)构造函数,字符串可以有多个副本。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接