2013-05-02 3 views
3

자바에서 명시 적 및 암시 인스턴스화하는 String 클래스의 차이점은 무엇입니까 Do not do this "그리고 새로운 String() 생성자를위한 하나! 그들은 -c와 함께 그러나 동일내가 두 번 인용 구문에 문자열의 두 인스턴스를 생성하기 때문에이</p> <pre><code>String s = new String("Don't do this"); // explicit </code></pre> <p>같은 문자열 인스턴스를 생성하는 "성능 문제가 있다고 들었습니다

C:\jav>javap String1 
Compiled from "String1.java" 
public class String1 extends java.lang.Object{ 
    public String1(); 
    public static void main(java.lang.String[]); 
} 

C:\jav>javap String2 
Compiled from "String2.java" 
public class String2 extends java.lang.Object{ 
    public String2(); 
    public static void main(java.lang.String[]); 
} 

같다 : 여기

public class String1 { 
public static void main(String[] args) { 
    String s = new String("Hello"); 
    System.out.println(s); 
} 
} 

public class String2 { 
public static void main(String[] args) { 
    String s = "Hello"; 
    System.out.println(s); 
} 
} 

은은 javap의 출력 :

오늘은 내가 두 개의 클래스를 만들어 내 자신에 의해 그것을 테스트하는 시간을 가졌다 플래그는 출력이 다릅니다. 그래서 여기

C:\jav>javap -c String1 
Compiled from "String1.java" 
public class String1 extends java.lang.Object{ 
public String1(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: new  #2; //class java/lang/String 
    3: dup 
    4: ldc  #3; //String Hello 
    6: invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V 
    9: astore_1 
    10: getstatic  #5; //Field java/lang/System.out:Ljava/io/PrintStream; 
    13: aload_1 
    14: invokevirtual #6; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    17: return 

} 


C:\jav>javap -c String2 
Compiled from "String2.java" 
public class String2 extends java.lang.Object{ 
public String2(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String Hello 
    2: astore_1 
    3: getstatic  #3; //Field java/lang/System.out:Ljava/io/PrintStream; 
    6: aload_1 
    7: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    10: return 

} 

내 질문입니다 :) 최초의 "LDC는"무엇을, astore_1 등? 그 (것)들을 기술하는 어떤 문서 있는가? 초 javac이 실제로이 두 문장이 동일하지 않은 것을 알 수 없습니까 ??

+0

[Java 가상 시스템 사양] (http://docs.oracle.com/javase/specs/jvms/se7/html/)에서 이러한 의미를 알 수 있습니다. –

+1

'new String()'작업을 다시 한 번 말 했으니까요. 이 작업은 원래 문자열의 문자 배열을 "공유"하므로 모든 Java 생성자 중 가장 빠른 것입니다. (일부 이국적인 경우를 제외하고는 이것을 수행하는 데있어 아무런 의미가 없습니다.) –

+1

'String'을 명시 적으로 생성하면 다른 객체가 생성됩니다.이 객체는 초기화 값의 실제 문자열 내용 (char 배열)을 공유합니다. 따라서 여분의 객체의 오버 헤드가 있습니다. –

답변

2

Wikipedia has a very convenient summary of all the possible Java Bytecode instructions. 또한, 전체 그림을 얻기 위해, 그것은 정수 풀을 포함하여 파일의 전체 내용,보고, javap -v을 사용하는 것이 좋습니다 :

Classfile /.../String1.class 
    Last modified 02/05/2013; size 458 bytes 
    MD5 checksum e3c355bf648c7441784ffc6b9765ba4d 
    Compiled from "String1.java" 
public class String1 
    SourceFile: "String1.java" 
    minor version: 0 
    major version: 51 
    flags: ACC_PUBLIC, ACC_SUPER 
Constant pool: 
    #1 = Methodref   #8.#17   // java/lang/Object."<init>":()V 
    #2 = Class    #18   // java/lang/String 
    #3 = String    #19   // Hello 
    #4 = Methodref   #2.#20   // java/lang/String."<init>":(Ljava/l 
ang/String;)V 
    #5 = Fieldref   #21.#22  // java/lang/System.out:Ljava/io/Prin 
tStream; 
    #6 = Methodref   #23.#24  // java/io/PrintStream.println:(Ljava 
/lang/String;)V 
    #7 = Class    #25   // String1 
    #8 = Class    #26   // java/lang/Object 
    #9 = Utf8    <init> 
    #10 = Utf8    ()V 
    #11 = Utf8    Code 
    #12 = Utf8    LineNumberTable 
    #13 = Utf8    main 
    #14 = Utf8    ([Ljava/lang/String;)V 
    #15 = Utf8    SourceFile 
    #16 = Utf8    String1.java 
    #17 = NameAndType  #9:#10   // "<init>":()V 
    #18 = Utf8    java/lang/String 
    #19 = Utf8    Hello 
    #20 = NameAndType  #9:#27   // "<init>":(Ljava/lang/String;)V 
    #21 = Class    #28   // java/lang/System 
    #22 = NameAndType  #29:#30  // out:Ljava/io/PrintStream; 
    #23 = Class    #31   // java/io/PrintStream 
    #24 = NameAndType  #32:#27  // println:(Ljava/lang/String;)V 
    #25 = Utf8    String1 
    #26 = Utf8    java/lang/Object 
    #27 = Utf8    (Ljava/lang/String;)V 
    #28 = Utf8    java/lang/System 
    #29 = Utf8    out 
    #30 = Utf8    Ljava/io/PrintStream; 
    #31 = Utf8    java/io/PrintStream 
    #32 = Utf8    println 
{ 
    public String1(); 
    flags: ACC_PUBLIC 
    Code: 
     stack=1, locals=1, args_size=1 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init> 
":()V 
     4: return 
     LineNumberTable: 
     line 1: 0 

    public static void main(java.lang.String[]); 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=3, locals=2, args_size=1 
     0: new   #2     // class java/lang/String 
     3: dup 
     4: ldc   #3     // String Hello 
     6: invokespecial #4     // Method java/lang/String."<init> 
":(Ljava/lang/String;)V 
     9: astore_1 
     10: getstatic  #5     // Field java/lang/System.out:Ljav 
a/io/PrintStream; 
     13: aload_1 
     14: invokevirtual #6     // Method java/io/PrintStream.prin 
tln:(Ljava/lang/String;)V 
     17: return 
     LineNumberTable: 
     line 3: 0 
     line 4: 10 
     line 5: 17 
} 

을 그리고 지금은 상수 곳 ldc 부하에서 분명하다.

javac가 이러한 최적화에 신경을 쓰지 않는 이유에 대한 질문은 Java에서 수행 한 거의 모든 최적화가 런타임에 지연되어 다른 컴파일러가 실행되는 이유입니다. Java 바이트 코드를 기본 시스템으로 컴파일하는 JIT 컴파일러 암호. javac은 "일반적인"사례를 최적화하기 위해 노력하지만 지터의 공격성과는 거리가 있습니다.

0

이 질문에 대한 대답은 기본 질문이지만 대답은 확실하지 않다고 생각합니다. Difference between string object and string literal 여기서 중요한 것은 인턴이 될 수 있다는 것입니다. 물론 equals 메소드가 무엇인지 알아낼 수 있습니다. ==는 객체 동등성을 테스트하는 것이고, 첫 번째 경우에는 java가 별도의 객체로 인스턴스화해야합니다.

2

ldc, astore_n, ...은 바이트 코드 명령어입니다. 이 목록은 Wikipedia에 있으며 자세한 내용은 JVM specification을 참조하십시오.

ldc은 추가 명령을 위해 스택에 상수 (여기서 문자열)를 푸시합니다. astore_1은 스택의 맨 위에있는 값을 로컬 변수 # 1에 저장합니다 (로컬 변수 # 0은 메소드의 매개 변수입니다). 따라서 두 번째 예제에서는 상수에서 "Hello"을로드하고 로컬 변수 # 1에 저장합니다.

첫 번째 구현에서는 String이라는 새 인스턴스가 만들어지고 로컬 변수 # 1에 저장되는 것을 보여줍니다. 따라서 두 번째 코드 조각보다 효율성이 떨어집니다. 게다가, 첫 번째 구현에서 ==을 사용하여 두 문자열을 비교할 수 없습니다. 이는 동일한 인스턴스가 아니며 새 문자열이 인 텐트되지 않기 때문입니다.