我對這兩件事感到困惑。我需要幫助。請明確我的疑問,String Constant Pool和String pool是否都是相同的概念。面試時我遇到了這個問題。我已經閱讀了很多網站和博客,但是,我的疑問沒有清除。請清除我的疑惑。字符串常量池vs字符串池
在此先感謝。
我對這兩件事感到困惑。我需要幫助。請明確我的疑問,String Constant Pool和String pool是否都是相同的概念。面試時我遇到了這個問題。我已經閱讀了很多網站和博客,但是,我的疑問沒有清除。請清除我的疑惑。字符串常量池vs字符串池
在此先感謝。
兩者都是一樣的東西。字符串常量池包含常量字符串對象。 Constant
可以定義爲String對象在編譯時保存該值。有關更多信息,請參閱JLS。
String s="abc";
String s1="def";
String s2=s+"def";
String s3="abc"+"def";
System.out.println(s2==s3); // print false
但是,如果你s
作爲最終然後
final String s="abc";
String s1="def";
String s2=s+"def";
String s3="abc"+"def";
System.out.println(s2==s3); // print true
在上述情況下s3
是一個編譯時間常數s是最後的。
感謝您的回答。 –
我想過了,我不確定,但字符串池可能引用字符串文字池,像String apple = "apple";
這樣的東西,作爲字符串常量池可能引用常量字符串對象,如那些使用關鍵字最終,雖然接受一個棘手的語義問題就像這樣會讓我很煩,如果我在採訪中得到它
謝謝你的回答。可能你是對的。 –
字符串池中(=「字符串常量池」):
這是考慮到字符串的類級/靜態實習生存儲非正式暱稱。注意:javadoc提到「字符串池」http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern%28%29。
這是一個包含應用程序執行過程中實現的每個唯一字符串值的集合。對於所有編譯時的字符串常量(文字和固定表達式)以及調用String.intern()
的所有運行時字符串值,會自動進行實習。 JLS要求編譯時常量表達式的字符串總是「被實施」,以便使用方法String.intern共享唯一實例。 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28
JVM規範沒有爲對象指定任何特定的內部結構。 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.7
Java語言規範確實要求String對象具有常量(不變)值。 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.3.3
這意味着一個String變量只能通過引用具有新值的新String對象來更改值 - 當然,這是由編譯器& JVM進行內部管理的。這也意味着池中的所有項目都是字符串常量。
常量池(未集中在字符串,但是包括字符串):
謝謝你:) –
字符串池(字符串常量/存儲器/字面普爾)對常量池
當編譯器能夠滿足任何字符串文字,編譯器將其放入字符串常量池的。所有的方法或類變量引用該字符串常量池;
class MemoryModel { final String s = "abc"; String s5 = "abc";}
:
String s1 = "abc";
MemoryModel mm = new MemoryModel();
System.out.println("abc".hashCode()); //12345
System.out.println(mm.s.hashCode()); //12345
System.out.println(mm.s5.hashCode()); //12345
System.out.println(s1.hashCode()); //12345
字符串「ABC」會去串池,而S,S5將在課堂上MemoryModel的常量池(或運行時間常量池)去。 's1'是方法局部變量,所以它將被保存在JVM框架中。
實施例2
public method(){
final String s="abc";
String s1="def";
final String s2=s+s1;
String s3=s+"def";
String s4="abc"+"def";
}
對於上述方法沒有將被保存在類的常量池。 「abc」,「def」和「abcdef」將被保存在字符串池中。
"abcdef".hashCode() == ("abc" + "def").hashCode() //true
上述方法的字節碼;
0: ldc #19 // String abc
2: astore_1
3: ldc #21 // String def
5: astore_2
6: new #23 // class java/lang/StringBuilder
9: dup
10: ldc #19 // String abc
12: invokespecial #25 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
15: astore_3
16: aload_3
17: aload_2
18: invokevirtual #28 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #32 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore 4
26: ldc #36 // String abcdef
28: astore 5
30: ldc #36 // String abcdef
32: astore 6
34: return
以上字節碼錶示沒有任何東西放入CP(常量池)。對於上面的代碼s3 == s4和s3 ==「abcdef」,因爲在編譯時所有的最終常數都被它們的值替換。所以上面的代碼會被轉換成這個;
final String s="abc";
String s1="def";
final String s2=new StringBuilder("abc").append(s1).toString();
String s3="abc"+"def";
String s4="abc"+"def";
但是,如果「s」不是最終然後
String s="abc";
String s1="def";
final String s2=new StringBuilder(s).append(s1).toString();
String s3=new StringBuilder(s).append("def").toString();
String s4="abc"+"def";
在上面的代碼中,S2和S3將指向具有字符字符串[]的新實例。所以s3和s4不一樣。
實施例3
public class MemoryModel {
final String s="abc";
String s1="def";
final String s2=s+s1;
String s3=s+"def";
String s4="abc"+"def";
String s5=s2;
}
字節碼本是相當多類似於上述字節碼。但是您會看到putfield
和getfield
的更多條目,它告訴我們常數被放入CP中。
我們來比較上面代碼的字節碼;
隨着最後的'
21: ldc #8 // String abc
23: invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
26: aload_0
27: getfield #23 // Field s1:Ljava/lang/String;
30: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
33: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
36: putfield #38 // Field s2:Ljava/lang/String;
沒有最終的'
21: aload_0
22: getfield #18 // Field s:Ljava/lang/String;
25: invokestatic #26 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
28: invokespecial #32 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
31: aload_0
32: getfield #22 // Field s1:Ljava/lang/String;
35: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
41: putfield #43 // Field s2:Ljava/lang/String;
而且
隨着最後的'
39: aload_0
40: ldc #40 // String abcdef
42: putfield #42 // Field s3:Ljava/lang/String;
沒有最終的'
44: aload_0
45: new #24 // class java/lang/StringBuilder
48: dup
49: aload_0
50: getfield #18 // Field s:Ljava/lang/String;
53: invokestatic #26 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
56: invokespecial #32 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
59: ldc #20 // String def
61: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
64: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
67: putfield #45 // Field s3:Ljava/lang/String;
這種比較也證明了最後變量的值被替換在比較時。常量字段保存到CP中。所以如果's'不是最終的,那麼's'的值是使用getfield從CP中獲取的。
我認爲他們是一樣的,這是一個很奇怪的面試問題 – aaronman
1+這個迴應。我雖然如此,但我已經面臨和困惑。 –
我可以問問你哪裏有這個問題 – aaronman