2013-05-28 47 views
1

我對這兩件事感到困惑。我需要幫助。請明確我的疑問,String Constant Pool和String pool是否都是相同的概念。面試時我遇到了這個問題。我已經閱讀了很多網站和博客,但是,我的疑問沒有清除。請清除我的疑惑。字符串常量池vs字符串池

在此先感謝。

+3

我認爲他們是一樣的,這是一個很奇怪的面試問題 – aaronman

+0

1+這個迴應。我雖然如此,但我已經面臨和困惑。 –

+0

我可以問問你哪裏有這個問題 – aaronman

回答

4

兩者都是一樣的東西。字符串常量池包含常量字符串對象。 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是最後的。

+0

感謝您的回答。 –

2

我想過了,我不確定,但字符串池可能引用字符串文字池,像String apple = "apple";這樣的東西,作爲字符串常量池可能引用常量字符串對象,如那些使用關鍵字最終,雖然接受一個棘手的語義問題就像這樣會讓我很煩,如果我在採訪中得到它

+0

謝謝你的回答。可能你是對的。 –

3

字符串池中(=「字符串常量池」):

常量池(未集中在字符串,但是包括字符串):

+0

謝謝你:) –

0

字符串池(字符串常量/存儲器/字面普爾)對常量池

當編譯器能夠滿足任何字符串文字,編譯器將其放入字符串常量池的。所有的方法或類變量引用該字符串常量池;

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框架中。

enter image description here

  • 字符串文字總是指String類的同一個實例。
  • 任何包中任何類的字符串表示對同一個String對象的引用 。
  • 通過常量表達式計算的字符串在編譯時計算出來,然後視爲它們是文字。

實施例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; 
} 

字節碼本是相當多類似於上述字節碼。但是您會看到putfieldgetfield的更多條目,它告訴我們常數被放入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中獲取的。