原java檔案:
package com.jyds;
/**
* * Created by jl on 2018/7/26 0026
* */
public class Test {
public static void main(String[] args) {
String a = "1";
String b = "2";
String c = a+b;
}
}
javac編譯後的class檔案:
cafe babe 0000 0034 002e 0a00 0900 1509
0016 0017 0700 180a 0003 0015 0a00 0300
1908 001a 0a00 0300 1b0a 0003 001c 0700
1d0a 001e 001f 0a00 0300 2007 0021 0100
063c 696e 6974 3e01 0003 2829 5601 0004
436f 6465 0100 0f4c 696e 654e 756d 6265
7254 6162 6c65 0100 046d 6169 6e01 0016 ...
javap -verbose 将.class檔案反編譯為可讀的位元組碼并輸出:
Classfile /home/ljiang/com/jyds/Test.class
Last modified Jul 26, 2018; size 458 bytes
MD5 checksum 5bd08e536acec4ae68ee147fee12e206
Compiled from "Test.java"
public class com.jyds.Test
SourceFile: "Test.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#18 // java/lang/Object."<init>":()V
#2 = String #19 // 1
#3 = String #20 // 2
#4 = Class #21 // java/lang/StringBuilder
#5 = Methodref #4.#18 // java/lang/StringBuilder."<init>":()V
#6 = Methodref #4.#22 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = Methodref #4.#23 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#8 = Class #24 // com/jyds/Test
#9 = Class #25 // java/lang/Object
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 SourceFile
#17 = Utf8 Test.java
#18 = NameAndType #10:#11 // "<init>":()V
#19 = Utf8 1
#20 = Utf8 2
#21 = Utf8 java/lang/StringBuilder
#22 = NameAndType #26:#27 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#23 = NameAndType #28:#29 // toString:()Ljava/lang/String;
#24 = Utf8 com/jyds/Test
#25 = Utf8 java/lang/Object
#26 = Utf8 append
#27 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#28 = Utf8 toString
#29 = Utf8 ()Ljava/lang/String;
{
public com.jyds.Test();
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 6: 0
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: ldc #2 // String 1
2: astore_1
3: ldc #3 // String 2
5: astore_2
6: new #4 // class java/lang/StringBuilder
9: dup
10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: return
LineNumberTable:
line 8: 0
line 9: 3
line 10: 6
line 11: 25
}
上述位元組碼指令解釋
ldc 将int, float或String型常量值從常量池中推送至棧頂
astore_1 将棧頂引用型數值存入第二個本地變量
invokevirtual 調用虛方法,具體實作在運作時會去判斷的
從位元組碼可以看出上述代碼是沒有new String對象的(隻new了一次StringBuilder,并可以看出編譯器将"+"操作優化為StringBuilder.append了),沒有new String對象是因為沒有顯示的new String(),這些值在位元組碼的常量池中可以找到,運作時會被直接儲存到本地變量區(由astore指令可以看出)。