Java中的字符串相等检查

时间:2019-06-25 04:45:29

标签: java string memory hashcode

以下两个语句之间的区别:

  1. String s = "Hello";
  2. String s = new String("Hello');

first 语句中,赋值运算符-用于将字符串文字分配给String变量s。在这种情况下; JVM首先检查字符串常量池中是否已经有相同的对象。如果可用,则创建另一个引用。如果同一对象不可用,则它将创建另一个内容为“ Hello”的对象,并将其存储到字符串常量池中。

第二语句中,new运算符用于创建字符串对象。在这种情况下,JVM总是在不查看字符串常量池的情况下创建新对象。

我在下面提供的代码中所遇到的疑问是语句的输出

System.out.println(a.hashCode() + " " + b.hashCode());

根据规则,这两个对象都应具有不同的内存位置,但是两个对象的哈希码都显示true

import java.util.HashMap;
import java.util.Map;

class TestStringEquality 
{ 
public static void main (String[] args) 
{ 

    String a = new String("abcd");
    String b = new String("abcd");

    System.out.println(a == b);
    System.out.println(a.hashCode() + " " + b.hashCode());
    System.out.println(a.equals(b));

    Map<String, String> map = new HashMap<>();

    map.put(new String("abcd"), "abcd");
    map.put(new String("abcd"), "wxyz");


    System.out.println(map);
} 
}

我得到的输出如下:

false
2987074 2987074
true
{abcd=wxyz}

5 个答案:

答案 0 :(得分:4)

根据https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#hashCode--上的API表 字符串的哈希码中使用的公式取决于字符串的长度和内容,而不取决于存储位置。因此,两个具有不同内存位置的相同字符串应该给出相同的哈希码。

答案 1 :(得分:3)

Java有一个名为String Pool的概念。程序中使用的每个字符串都将作为缓存机制存储在池中。

例如下面的代码:

String a = "StackOverFlow";  // Java will push StackOverFlow into string pool
String b = "StackOverFlow";  // Java will get address of "StackOverFlow" object in string pool and assigned to b.

在Java中,程序员不必直接使用指针。但是,指针仍然在这里。使用运算符“ ==”时,原始数据类型变量(例如int,short…)将按它们的值进行比较。但是在String中,Java将通过它们的地址进行比较。

这就是以下行将返回true的原因:

System.out.println(a == b); // true

但是,当您调用new String(...)时,Java将创建一个新的字符串对象。它不会查看字符串池来检查字符串值是否已存储在字符串池中。这就是两个变量具有相同值,但它们的地址仍不同的原因,因此“ ==“运算符将返回false。

String a = "StackOverFlow";
String b = new String("StackOverFlow"); // new string object. not use old one in String Pool.
System.out.println(a == b); // False. because they have different addresses. 

由于有字符串池机制,比较两个对象时必须使用equals方法。这样,我们就不必在意该String对象是如何构建的。因此,以下代码始终返回true:

String a = "StackOverFlow";
String b = "StackOverFlow";  // use same object as a
String c = new String("StackOverFlow"); // create new string
System.out.println(a.equals(b)); // true
System.out.println(a.equals(b)); // true
System.out.println(a.equals(c)); // true

关于哈希码,Java将使用哈希函数根据字符串的字符来计算值。这样,无论如何构建字符串,如果2个字符串的值相等,它们将具有相同的哈希码。

String a = "StackOverFlow";
String b = "StackOverFlow";  // use same object as a
String c = new String("StackOverFlow"); // create new string
System.out.println(a.hashCode() == b.HashCode()); // true
System.out.println(a.hashCode() == c.HashCode()); // true

基于讨论,我们可以得出以下结论。如果2个字符串具有相同的哈希码,则我们无法确认运算符“ ==”返回true。因为它们可能是相同的值,但是它们是堆内存中的不同对象。

但反之亦然。如果2个字符串指向相同的地址,则它们将具有相同的值,因此具有相同的哈希码。

有趣的问题:如果两个字符串具有相同的哈希码,我们可以假定这两个字符串相等吗?

答案 2 :(得分:1)

我认为您在普通堆内存和字符串常量池之间感到困惑。当您检查是否相等时,JVM会为您获取存储在普通堆内存中的对象,对象是相同的。它们仅在字符串常量池中有所不同。这就是为什么'=='返回false的原因,因为字符串常量池中的位置不同,因为副本具有不同的引用,但是equals返回true,因为两者的类型相同且持有相似的字符串。

答案 3 :(得分:1)

“ Object”类的hashCode()实现返回基础内存位置。

hashCode()实现的“字符串”将覆盖Object中的hashCode()。返回此字符串的哈希码。字符串对象的哈希码计算为

s [0] * 31 ^(n-1)+ s [1] * 31 ^(n-2)+ ... + s [n-1]

此外,这使程序员的生活更轻松。例如,我们可以使用硬编码的字符串键查询Map,而不必将原始键对象保留在我们身边。

答案 4 :(得分:0)

此字符串相等时可以使用哈希码方法。 但是,为了获得更好的性能使用

String firstString = "string1";
String secondString = "String1";
println(" it will return boolean " + firstString.equal(secondString ) + " "); //false
println(" it will return boolean " + firstString.equalIgnoreCase(secondString ) + " "); //true