簡體   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