原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指令可以看出)。