나는이 두 가지에 대해 혼란스러워합니다. 도움이 필요해. 문자열 상수 풀과 문자열 풀이 모두 같은 개념인지 의심해보십시오. 나는 인터뷰에서이 질문에 직면했다. 이미 많은 사이트와 블로그를 읽었지만 내 의심은 사라지지 않았습니다. 제 의심을 분명히하십시오.문자열 상수 풀과 문자열 풀
미리 감사드립니다.
나는이 두 가지에 대해 혼란스러워합니다. 도움이 필요해. 문자열 상수 풀과 문자열 풀이 모두 같은 개념인지 의심해보십시오. 나는 인터뷰에서이 질문에 직면했다. 이미 많은 사이트와 블로그를 읽었지만 내 의심은 사라지지 않았습니다. 제 의심을 분명히하십시오.문자열 상수 풀과 문자열 풀
미리 감사드립니다.
에있어 경우에 그 날 성가 시게하는 것처럼 까다로운 의미로 질문을받을 모두 같은 일이다. 문자열 상수 풀 상수 문자열 개체가 들어 있습니다. 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는 최종으로 일정한 컴파일 시간입니다.
답장을 보내 주셔서 감사합니다. –
나는 그것에 대해 생각하지만 문자열 풀은 문자열 리터럴 풀을 참조 할 수 있습니다. String apple = "apple";
같은 문자열 상수 풀은 키워드 최종을 사용하는 것과 같은 상수 문자열 개체를 참조 할 수 있습니다. 내가 인터뷰
이 답변을 주셔서 감사합니다. 당신이 옳을 수도 있습니다. –
문자열 풀 (= "문자열 상수 풀") :
이 문자열의 클래스 레벨/정적 인턴 스토리지에 주어진 비공식 별명이다. 주 : javadoc에는, 「캐릭터 라인 풀」http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern%28%29가 포함되어 있습니다.
그것은 응용 프로그램을 실행하는 동안 구금마다 고유의 문자열 값을 포함하는 설정입니다. 모든 컴파일시 문자열 상수 (리터럴 및 고정 표현식)와 String.intern()
이 호출되는 모든 런타임 문자열 값에 대해 자동으로 수행됩니다. JLS에서는, String.intern 메소드를 사용해, 일의의 인스턴스를 공유하기 위해서, String 형의 컴파일시의 상수 표현은 항상 「계승」되고있을 것을 요구합니다. 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 객체는 상수 (변하지 않는) 값을 갖는 것을 의무화 않습니다. String 변수 만 새로운 값을 가진 새로운 스트링 객체를 참조하여 값을 변경할 수 있다는 것을 의미 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.3.3
- 물론,이 내부 컴파일러 & JVM에 의해 관리된다. 즉, 풀의 모든 항목은 문자열 상수입니다. (로드 각 클래스 및 메모리)
정수 풀
은 (문자열에 초점을 맞추고 있지만, 문자열을 포함하지 않습니다). 사용중인 상수 (예 : 최종 변수)의 클래스 별 레코드입니까?http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.5감사합니다 :) –
문자열 풀 상수 풀 대 (문자열 상수/메모리/리터럴 풀)
컴파일러는 문자열 리터럴을 충족, 컴파일러는 문자열 상수 풀에 넣는다. 모든 메소드 또는 클래스 변수는 해당 문자열 상수 풀을 참조합니다.
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;
최종의'없이 최종의 '
,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의 값을 얻습니다.
나는 이것들이 같다고 생각한다.이 대답은 꽤 이상한 인터뷰 질문이다. – aaronman
1+. 그렇지만 나는 직면하고 혼란 스럽습니다. –
그 질문이있는 곳을 물어봐도됩니까 – aaronman