2014-12-30 10 views
18
public static void main(String[] args) { 

    String a = new String("lo").intern(); 
    final String d = a.intern(); 
    String b = "lo"; 
    final String e = "lo"; 
    String c = "Hello"; 
    System.out.println(b==a);//true 
    System.out.println(d==a);//true 
    System.out.println(e==a);//true 
    System.out.println(c=="Hel"+a); //why is this false? when e==a is true 
    System.out.println(c=="Hel"+d); //why is this false? 
    System.out.println(c=="Hel"+b); //why is this false? 
    System.out.println(c=="Hel"+e); //this is true 

} 

이 같은 기준을 의미

true 
true 
true 
false 
false 
false 
true 

e==a에 해당하는 표현을 발생합니다. 그렇다면 마지막 표현이 참인 이유는 무엇입니까? 예를 들어 c== "Hel"+a은 false입니까?

+0

나는 지난 4 개의 모든 것이 거짓이어야한다고 생각한다. 이 예를 들어 보겠습니다. – markspace

+1

u가 equals()를 사용해 보았습니다. –

+0

비슷한 질문을했는데 답변을 듣지 못했지만 필요한 경우가 아니라면 일반적으로 문자열을 사용할 가치가없는 것으로 나타났습니다. –

답변

16

표현

"Hel" + a 

컴파일 시간 상수가 아닙니다. 사실, 런타임에 새로운 String 객체를 생성하는

new StringBuilder().append("Hel").append(a).toString() 

(또는 이와 유사한 것)으로 컴파일됩니다. e 최종 때문에

그러나 컴파일러 "Hel"의 연결 및 e의 값이 상수 값이라고 판단 할 수 등을 인턴.

+0

이 완전히 실용적이지 않다는 것을 지적하면 String.valueOf()가 호출되어 toSTring()을 내부적으로 호출 할 것이라고 생각합니다. – Prashant

+0

@bohemian 당신은 c == "Hel"+ d가 거짓임을 알 수 있습니까? 여기에 d가 최종입니다 .. ?? –

10

모든 문자열이 런타임에 계산이 전자가 최종 때문에 그들이,

System.out.println(c=="Hel"+a); //why is this false? when e==a is true 
System.out.println(c=="Hel"+d); //why is this false? 
System.out.println(c=="Hel"+b); //why is this false? 

컴파일 시간에 계산이 하나의 다른 이유 :

System.out.println(c=="Hel"+e); //this is true 

이 코드를 변경하는 경우 :

System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true 
    System.out.println(c==("Hel"+d).intern()); //why is this false? 
    System.out.println(c==("Hel"+b).intern()); //why is this false? 

모두가 참을 수 있습니다.

+0

e가 최종이기 때문에''Hel "+ e''가 컴파일 타임 상수라는 JLS의 견적을 갖고 있습니까? 그것은 나를위한 새로운 것입니다. – markspace

+2

@markspace 정확한 인용문은 없지만 Java 컴파일러는 e가 최종이 되 자마자 상수 표현식 (이 경우 "Hel"+ e)을 평가합니다. - 컴파일러는 상수라고 가정합니다. –

+0

@markspace [Expressions] /docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28) –

5

Java compiler (javac)은 code in JavaJVM에 의해 실행되는 byte code으로 변환합니다. 또한 최적화를 수행합니다. c 여기 final 인이 조각의 바이트 코드이기 때문에 당신은

c==a에 해당하는 최종 문자열로 -c 매개 변수를

병합을 javap 유틸리티를 사용하여 생성 된 바이트 코드를 확인할 수 있습니다 (마지막 비교 만) :

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String Hello 
    2: astore_2 
    3: getstatic  #3; //Field java/lang/System.out:Ljava/io/PrintStream; 
    6: aload_2 
    7: ldc  #2; //String Hello 
    9: if_acmpne  16 
    12: iconst_1 
    13: goto 17 
    16: iconst_0 
    17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V 
    20: return 

} 

Java 컴파일러에서 "Hel"를 "lo"와 병합하고 "Hello"라는 두 문자열을 비교했습니다.자바는 기본적으로 문자열 리터럴을 인턴 - 그것은 당신이 아닌 최종 String 변수와 리터럴 문자열을 연결하는 경우

, 바이트 코드가 다를 수 final이 아닌 문자열로 진정한

병합을 돌려 그 이유는 : 여기

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String lo 
    2: astore_1 
    3: ldc  #3; //String Hello 
    5: astore_2 
    6: getstatic  #4; //Field java/lang/System.out:Ljava/io/PrintStream; 
    9: aload_2 
    10: new  #5; //class java/lang/StringBuilder 
    13: dup 
    14: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V 
    17: ldc  #7; //String Hel 
    19: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    22: aload_1 
    23: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    26: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    29: if_acmpne  36 
    32: iconst_1 
    33: goto 37 
    36: iconst_0 
    37: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V 
    40: return 

} 

우리는 분명히 다른 객체를 반환 java/lang/StringBuilder.toString:()Ljava/lang/String; 방법의 결과를 비교하는 - 그것은 "안녕하세요"에 값을 기준으로하지만 참조

로 동일 당신이 intern() 방법을 사용하더라도 17,451,515,

당신이 stackoverflow question

+0

바이트 코드에 익숙하지 않다면 더 많은 설명을 추가 할 수 있습니다. –

+0

@SumeetSharma 좀 더 자세한 내용을 추가했습니다. 희망이 지금은 분명하다 – bedrin

+0

바이트 코드에 대한 통찰력을 가져 주셔서 감사합니다. 후드 물건 아래 작동에 대한 이해가 매우 유용했습니다. 그러나 저는 보헤미아가 내가 찾던 것에 더 관련이있는 답을 발견했습니다. :) 어쨌든 고마워. 나는 upvote를 주었다. –

1

에서 비교 문자열에 대한 자세한 정보를 찾을 수 있습니다, 당신은 여전히 ​​==는 참조가 아닌 값으로 비교 것을 기억해야합니다. 그래서

System.out.println(c=="Hel"+a); 
    System.out.println(c=="Hel"+d); 
    System.out.println(c=="Hel"+b); 

"Hel" + a 또는 "Hel" + d 또는 "Hel" + b의 경우

c의 것과 동일하지 않은 메모리에 새로운 기준을 가질 것이다.

문자열 값이 최종이므로 평가가 변경되지 않으므로 최적화 대신 런타임 대신 컴파일 타임에 발생합니다. 또한 문자열 리터럴을 정의 할 때 생각 중이라면 Java는 내부적으로이를 처리합니다.