我對Java中的StringPool感到困惑。我在閱讀Java中的String章節時遇到了這個問題。用通俗的話來說,請幫助我理解StringPool實際做了什麼。什麼是Java中的字符串池?
回答
這將打印true
(儘管我們不使用equals
方法:正確的方式來比較字符串)
String s = "a" + "bc";
String t = "ab" + "c";
System.out.println(s == t);
當編譯器優化您的字符串常量,它認爲這兩個s
和t
具有相同的價值,從而你只需要一個字符串對象。這是安全的,因爲String
在Java中是不可變的。
因此,s
和t
指向相同的對象並保存一些小內存。
名稱的'字符串池'來自這樣的想法,即所有已定義的字符串都存儲在某個「池」中,並且在創建新對象之前,對象編譯器檢查是否已經定義了這樣的字符串。
我不認爲它確實有很大的作用,它看起來就像是字符串文字的緩存。如果您有多個字符串的值相同,則它們都將指向字符串池中的相同字符串字面值。
String s1 = "Arul"; //case 1
String s2 = "Arul"; //case 2
在情況1中,文字s1被新創建並保存在池中。但在情況2中,文字s2引用s1,它不會創建新的。
if(s1 == s2) System.out.println("equal"); //Prints equal.
String n1 = new String("Arul");
String n2 = new String("Arul");
if(n1 == n2) System.out.println("equal"); //No output.
當JVM裝載類,或以其他方式看到文字字符串,或一些代碼intern
SA字符串,它添加字符串到具有每個這樣的一個拷貝大多隱藏查找表串。如果添加了另一個副本,則運行時會對其進行排列,以便所有文字都引用相同的字符串對象。這被稱爲「實習」。如果你這樣說
String s = "test";
return (s == "test");
它會返回true
,因爲第一和第二個「測試」實際上是同一個對象。這樣比較interned字符串可能比String.equals
更快,因爲只有一個參考比較,而不是一堆char
比較,所以多得多比String.equals
更快。
您可以通過調用String.intern()
將字符串添加到池中,該字符串將返回字符串的合併版本(可能與您正在實習的字符串相同,但您會爲此瘋狂地依賴該字符串 - - 你經常無法確定哪些代碼已經被加載並直到現在運行並實現相同的字符串)。合併版本(從intern
返回的字符串)將等於任何相同的文字。例如:
String s1 = "test";
String s2 = new String("test"); // "new String" guarantees a different object
System.out.println(s1 == s2); // should print "false"
s2 = s2.intern();
System.out.println(s1 == s2); // should print "true"
我其實並不認爲這是在運行時完成的。即使使用方法構造的最簡單的字符串也不會被合併。例如。,如果我使用_concat_而不是_con __ _ – 2010-09-27 06:41:07
@Nikita:那麼我的答案中的示例將不起作用,這是因爲'concat'不能被輕鬆優化。用'+'拼湊在一起的字符串可能會被任何自尊的編譯器預先收集,因爲值永遠不會改變。但是編譯器無法真正猜測一個函數是否會一直返回相同的值(有些不會),所以它不會嘗試。如果在你的例子中使用'concat'而不是「ab」,「c」,「a」和「bc」,但「abc」不會(因爲它不是一個文字, t' intern' it)。然而,用'+'編譯器會看到這兩個字符串都是「abc」並編譯它。 – cHao 2010-09-27 08:25:42
實習將*在*運行時完成,因爲(1)池總是空出來的,(2)兩個不同的類每個都可以有「abc」。如果interning是編譯時的事情,並且兩個類最終都被加載,那麼最終會在字符串池中出現兩個「abc」,這會破壞字符串池的整個目的。 – cHao 2010-09-27 08:45:28
讓我們開始從虛擬機規格報價:
加載包含文字可能會創建一個新的String對象的String類或接口(§2.4.8)來表示該文字。如果已經創建了一個String對象來表示該文本的先前出現,或者如果String.intern方法已經在表示與文字相同的字符串的String對象上被調用,則可能不會發生這種情況。
這可能不會發生 - 這是一個暗示,那有什麼特殊String
對象。通常,調用一個構造函數將會總是創建一個新的類實例。對於字符串來說情況並非如此,尤其是當字符串對象用文字「創建」時。那些字符串存儲在全局存儲(池)中 - 或者至少引用保存在一個池中,並且每當需要已知字符串的新實例時,vm都會從池中返回對該對象的引用。在僞代碼,它可能會這樣:
1: a := "one"
--> if(pool[hash("one")] == null) // true
pool[hash("one") --> "one"]
return pool[hash("one")]
2: b := "one"
--> if(pool[hash("one")] == null) // false, "one" already in pool
pool[hash("one") --> "one"]
return pool[hash("one")]
在這種情況下
所以,變量a
和相同對象b
保持引用。在這種情況下,我們有(a == b) && (a.equals(b)) == true
。
這是不是這樣,如果我們使用的構造函數:
1: a := "one"
2: b := new String("one")
再次,"one"
在該池上創建,但隨後我們創建從相同的字面一個新的實例,在這種情況下,它會導致(a == b) && (a.equals(b)) == false
所以爲什麼我們有一個字符串池嗎?字符串和特別是字符串文字被廣泛用於典型的Java代碼中。它們是不變的。不可變的被允許緩存String以節省內存並提高性能(減少創建工作量,減少垃圾收集)。
正如我們不必在意字符串池中,只要我們牢記程序員:
(a == b) && (a.equals(b))
可能true
或false
(總是使用equals
比較字符串)- 不要使用反射來改變字符串的支持
char[]
(因爲你不知道是誰在使用該字符串actualling)
如果您關心字符串池,那麼在廣泛使用一小組字符的應用程序中,可能會大幅提升性能,通常用作令牌或關鍵字。一旦字符串被執行,比較變成一個'==',而不是函數調用,兩個length()調用,以及'equals'可能發生的一堆字符比較。 – cHao 2010-09-27 09:09:51
@cHao爲了安全性和一致性,您仍然可以對字符串使用'String.equals()',因爲'String.equals()'首先執行'=='比較 – bcoughlan 2014-10-01 11:00:14
@bcoughlan:'=='是安全的,一致爲「平等」 - 這只是誤解。與物體一起使用的人分爲兩類。有些人不明白價值vs身份語義(並且==與引用類型比較身份) - 那些人*應該*總是使用'String.equals'。然後有些人明白,但有意識地選擇身份。只要你知道你的物體來自哪裏,那就可以可靠地工作。有一個原因,「==」與對象一起工作 - 特別是爲什麼它不只是調用equals。 – cHao 2014-10-01 14:02:00
- 1. 爲什麼字符串存儲在Java中的字符串池?
- 2. java字符串池中的內容
- 3. Java的字符串文字池
- 4. 是什麼堆內存和字符串常量池之間的Java
- 5. Java字符串常量池中
- 6. C#的@字符串文字在Java中對應的是什麼?
- 7. 什麼是Java字符串compareTo方法和什麼是Java字典序
- 8. Java字符串中負字節值的意義是什麼?
- 9. Java字符串池相關的疑惑
- 10. 關於Java的字符串池
- 11. 字符串常量池在java中是如何工作的
- 12. 爲什麼使用new運算符創建的字符串在字符串池中創建字符串literal
- 13. 什麼是空字符串?
- 14. 什麼是unicode字符串?
- 15. 什麼是Uri字符串?
- 16. 什麼是C#字符串
- 17. CSS中的`〜`代字符串是什麼?
- 18. {}中的字符串是什麼意思?
- 19. 什麼是.NET中的字符串?
- 20. 什麼是Perl中的「字符串化」?
- 21. Go中的字符串是什麼?
- 22. C#中字符串前的@是什麼?
- 23. 什麼是Java 8中的字符串鍵的替代散列?
- 24. 爲什麼java中的字符串是不可變的?
- 25. 在C#中的區別是什麼:字符串VS字符串
- 26. 從字符串池中分配字符串是否有效?
- 27. 什麼是Java中的字符串本地內存?
- 28. Java字符串中的底層容器是什麼?
- 29. Java常量池的用途是什麼?
- 30. 關於Java字符串常量池
的Java有原始類型的包裝類型,這些類也是不可變的。像Integer,Charecter和Double ....等。他們是否也有一個游泳池來節省內存?如果沒有,String有什麼特別之處? – 2015-02-02 09:21:05
@PunithRaj我並不確定!然而,我懷疑它。例如,int只有4個字節,所以最終不會因爲兩個Integer指向內存中的相同位置而節省太多。相反,不得不維護一個「整數池」來發現重複值,可能會浪費更多的內存,而不是通過避免重複值來節省。 – 2015-02-03 10:49:45
@PunithRaj字符串不是原始數據類型(技術上/執行方面明智)和字符串沒有像char/int如何做的包裝類。 – user3240361 2015-02-17 10:49:38