2013-05-28 5 views
1

나는이 두 가지에 대해 혼란스러워합니다. 도움이 필요해. 문자열 상수 풀과 문자열 풀이 모두 같은 개념인지 의심해보십시오. 나는 인터뷰에서이 질문에 직면했다. 이미 많은 사이트와 블로그를 읽었지만 내 의심은 사라지지 않았습니다. 제 의심을 분명히하십시오.문자열 상수 풀과 문자열 풀

미리 감사드립니다.

+3

나는 이것들이 같다고 생각한다.이 대답은 꽤 이상한 인터뷰 질문이다. – aaronman

+0

1+. 그렇지만 나는 직면하고 혼란 스럽습니다. –

+0

그 질문이있는 곳을 물어봐도됩니까 – aaronman

답변

4

에있어 경우에 그 날 성가 시게하는 것처럼 까다로운 의미로 질문을받을 모두 같은 일이다. 문자열 상수 풀 상수 문자열 개체가 들어 있습니다. Constant은 컴파일 타임에 값을 보유하는 String 객체로 정의 할 수 있습니다. 자세한 내용은 JLS을 참조하십시오. 위의 경우 다음

final String s="abc"; 
    String s1="def"; 
    String s2=s+"def"; 
    String s3="abc"+"def"; 
    System.out.println(s2==s3); // print true 

마지막으로 s을 할 경우

String s="abc"; 
    String s1="def"; 
    String s2=s+"def"; 
    String s3="abc"+"def"; 
    System.out.println(s2==s3); // print false 

는 그러나 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 클래스의 동일한 인스턴스를 나타냅니다.
  • 모든 패키지의 모든 클래스에있는 리터럴 문자열은 동일한 문자열 개체 에 대한 참조를 나타냅니다.
  • 상수 식에 의해 계산 된 문자열은 컴파일 타임에 계산 된 다음 리터럴 인 것처럼 처리됩니다.

위의 방법 아무것도 예를 들어 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; 

최종의'없이 최종의 '

,536,913와

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; 

그리고

을 가진

최종의 '

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; 

이 비교없이 63,210

39: aload_0 40: ldc #40 // String abcdef 42: putfield #42 // Field s3:Ljava/lang/String; 
는 최종 변수의 값을 비교시 대체되는 것을 증명한다. 그리고 상수 필드는 CP에 저장됩니다. 그래서 's'가 final이 아니라면 getfield를 사용하여 CP의 값을 얻습니다.