2014-06-23 2 views
5

다음 코드를 실행하고 주석에 표시된 결과를 얻습니다. ==.equals()의 차이점을 알고 있습니다. 두 번째 줄의 코드가 세 번째 줄의 코드와 다른 결과를 얻는 이유는 무엇인지 이해할 수 없습니다.Java에서 "abc"+ "de"와 "abc"+ de (de = "de")의 차이점은 무엇입니까?

  Code: 
0: ldc  #9; //String de 
2: astore_1 
3: new  #10; //class java/lang/StringBuilder 
6: dup 
7: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V 
10: ldc  #4; //String abc 
12: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang 
String;)Ljava/lang/StringBuilder; 
15: aload_1 
16: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang 
String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #13; //Method java/lang/StringBuilder.toString:()Ljava/l 
ng/String; 
    22: astore_2 
    23: getstatic  #14; //Field java/lang/System.out:Ljava/io/PrintStream; 
    26: invokevirtual #15; //Method java/io/PrintStream.println:()V 
    29: getstatic  #14; //Field java/lang/System.out:Ljava/io/PrintStream; 
    32: aload_2 
    33: ldc  #16; //String abcde 
    35: if_acmpne  42 
    38: iconst_1 
    39: goto 43 
    42: iconst_0 
    43: invokevirtual #17; //Method java/io/PrintStream.println:(Z)V 
    46: getstatic  #14; //Field java/lang/System.out:Ljava/io/PrintStream; 
    49: aload_1 
    50: ldc  #9; //String de 
    52: if_acmpne  59 
    55: iconst_1 
    56: goto 60 
    59: iconst_0 
    60: invokevirtual #17; //Method java/io/PrintStream.println:(Z)V 
    63: return 

그리고 두 번째 문자열 연결을위한 출력 :

String de = "de"; 
// String abcde = "abc" + "de"; // abcde == "abcde" reture true 
    String abcde = "abc" + de; // abcde == "abcde" reture false; 
    System.out.println(); 
    System.out.println(abcde=="abcde"); 
    System.out.println(de=="de"); 
난은 javap -c 명령 사용이 디버깅하는 노력에서

과 첫 번째 문자열 연결에 대한 다음과 같은 출력 '코드'를 가지고

나는이 '코드'너무 익숙하지 않은이고 이러한 차이가 존재하는 어떤 이유를 볼 수 없습니다. 왜 그런 차이가 발생하는지 설명 할 수 있습니까?

관련 post

+8

실제 질문은 무엇입니까? (나는'=='이 string * references *이 아닌 string * references *을 비교한다는 것을 이미 알고 있다고 가정합니다)? – NPE

+1

'String.equals (....) '메쏘드를 보라.'=='연산자와 같지 않다 ... – vikingsteve

+1

"그 코드"를 이해하려면 ... [http] : //docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html). –

답변

11

"문제"는 단순히 컴파일러가 너무 똑똑하다는 것입니다. "abc" + "de"을 보면 바로 그 문자를 "abcde"리터럴에 연결합니다. 이 "abc" + de을 볼 때 문자 그대로 해당 "최적화"를 (자바 규칙에 따라) 허용하지 않는다 대신 새로운 String 객체를 창조하는 + 기능을 구현해야합니다.

문자열 리터럴은 항상 인턴 문자열로 처리되므로 == 그들에 작동합니다.

+1

프로그램이 실제로 실행되기 전에도 "abc"+ "de"가 문자열 풀의 일부가되는 것을 의미합니까? – Tony

+3

@ 토니 - 컴파일러는 'String a = "abc"+ "de";와 같은 명령문이'String a = "abcde";'로 컴파일되도록 설계되었습니다. 이것은 의도적으로 다중 행 문자열 리터럴을'+'및 기타 이와 결합 할 수 있도록하기위한 것입니다. –

+1

인내심에 감사드립니다. 또 하나의 질문 : JVM 또는 메모리에 상수 풀이로드되는시기입니다. 감사. – Tony

3

문제는 당신이 ==로 문자열을 비교하는 것을의의 + 함께 할 수 없습니다.

짧은 답변 : 자바 ==에서 "string".equals("string2")

(예 : 문자열로) 객체와 함께 사용할 때 참조가 동일하다 사용; "이 두 이름이 메모리의 같은 대상을 가리 킵니까?"

Java는 매번 새로운 객체를 생성하는 대신 문자열을 사용할 수있는 문자열 풀을 가지고 있으므로 (문자열이 변경되지 않아서 문제가되지 않음) 컴파일러가 충분히 영리한 지 여부에 대한 진정한/거짓 문제가 발생합니다 두 문자열이 동일하거나 또는 같지 않으며 따라서 동일한 객체를 사용할 수 있다는 것을 인식해야합니다. 그것에 의지하지 마십시오.

+0

오해하게해서 죄송합니다. 내 편집을 참조하십시오. – Tony

2
String de = "de"; // "de" is set during compile time and placed in the "String Pool". 
// String abcde = "abc" + "de";// abcde == "abcde" reture true -- > String reference abcde will be set to "abcde" during compilation itself. and "abcde" will be placed in the String Pool. 
    String abcde = "abc" + de;   // abcde == "abcde" reture false; abcde will not be set during compilation as the value of reference de will be resolved during runtime. 
    System.out.println(); 
    System.out.println(abcde=="abcde");// false as --> String literal "abcde" on String pool != String Object "abcde" on heap. 
    System.out.println(de=="de");// true--> de points to "de" on String pool 
1

Java 컴파일러의 아티팩트입니다. 알다시피, ==은 객체 참조를 비교하지만 내용을 비교하지 않습니다. 소스 코드에서 볼

자바 컴파일러 인턴에게 노출 된 문자열. 따라서 "x"=="x""x" 문자열의 사본이 하나뿐이기 때문에 소스 코드에서 가져온 것이므로 값이 "x" 인 파일에서 문자열을 읽는 것이 같은 개체가 아니기 때문에 "x" 인 은 이 아니기 때문입니다.

자바 컴파일러는 문자열에 + 운영자에 대한 영리하다. 내부적으로 var+"x"new StringBuffer().append(var).append("x").toString()으로 변환합니다. 그러나 문자열을 함께 결합하고 다른 문자열 (예 : "abc"+"de"는 구금 문자열 "abcde"하지 new StringBuffer().append("abc").append("de").toString()가 발생합니다.