繁体   English   中英

java中的字符串相等检查

[英]String equality check in java

以下两种说法的区别:

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

第一条语句中,赋值运算符-用于将字符串文字赋值给字符串变量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}

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

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. 

由于 String Pool 机制,我们在比较两个对象时必须使用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 个字符串具有相同的哈希码,我们不能确认运算符“==”返回真。 因为它们可能是相同的值,但它们是堆内存上的不同对象。

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

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

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

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

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

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

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

这个字符串相等你可以使用 hashcode 方法。 但是,为了更好的性能使用

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM