深入理解字节码点击这里
jdk中的bin里面自带有反编译的程序,叫javap.exe,利用他可以从编译生成的.class查看出对应的字节码代码
具体方法如下:
1.javap -verbose ** >> **.txt
例:
随便写个java类Person
class Person{
String name;
char sex;
int age;
Person(){
}
Person(String name,char sex,int age){
this.name=name;
this.sex=sex;
this.age=age;
}
String toString(int a){
return(String.valueOf(a));
}
String toString(char a){
return(String.valueOf(a));
}
}
编译生成.class后,放到桌面上,shift+右键在当前窗口打开命令行(win7可以,xp不行,就是去.class对应的目录输入命令)输入
javap -verbose Person >> Person.txt
然后在桌面上就看到了Person.txt
内容:
Classfile /C:/Users/linux_v/Desktop/Person.class
Last modified Oct 11, 2012; size 589 bytes
MD5 checksum 137de4fcce084d25ffb5c93b1708f63a
Compiled from "Person.java"
class Person
SourceFile: "Person.java"
minor version: 0
major version: 51
flags: ACC_SUPER
Constant pool:
#1 = Methodref #8.#25 // java/lang/Object."<init>":()V
#2 = Fieldref #7.#26 // Person.name:Ljava/lang/String;
#3 = Fieldref #7.#27 // Person.sex:C
#4 = Fieldref #7.#28 // Person.age:I
#5 = Methodref #29.#30 // java/lang/String.valueOf:(I)Ljava/lang/String;
#6 = Methodref #29.#31 // java/lang/String.valueOf:(C)Ljava/lang/String;
#7 = Class #32 // Person
#8 = Class #33 // java/lang/Object
#9 = Utf8 name
#10 = Utf8 Ljava/lang/String;
#11 = Utf8 sex
#12 = Utf8 C
#13 = Utf8 age
#14 = Utf8 I
#15 = Utf8 <init>
#16 = Utf8 ()V
#17 = Utf8 Code
#18 = Utf8 LineNumberTable
#19 = Utf8 (Ljava/lang/String;CI)V
#20 = Utf8 toString
#21 = Utf8 (I)Ljava/lang/String;
#22 = Utf8 (C)Ljava/lang/String;
#23 = Utf8 SourceFile
#24 = Utf8 Person.java
#25 = NameAndType #15:#16 // "<init>":()V
#26 = NameAndType #9:#10 // name:Ljava/lang/String;
#27 = NameAndType #11:#12 // sex:C
#28 = NameAndType #13:#14 // age:I
#29 = Class #34 // java/lang/String
#30 = NameAndType #35:#21 // valueOf:(I)Ljava/lang/String;
#31 = NameAndType #35:#22 // valueOf:(C)Ljava/lang/String;
#32 = Utf8 Person
#33 = Utf8 java/lang/Object
#34 = Utf8 java/lang/String
#35 = Utf8 valueOf
{
java.lang.String name;
flags:
char sex;
flags:
int age;
flags:
Person();
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 5: 0
line 6: 4
Person(java.lang.String, char, int);
flags:
Code:
stack=2, locals=4, args_size=4
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field name:Ljava/lang/String;
9: aload_0
10: iload_2
11: putfield #3 // Field sex:C
14: aload_0
15: iload_3
16: putfield #4 // Field age:I
19: return
LineNumberTable:
line 7: 0
line 8: 4
line 9: 9
line 10: 14
line 11: 19
java.lang.String toString(int);
flags:
Code:
stack=1, locals=2, args_size=2
0: iload_1
1: invokestatic #5 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
4: areturn
LineNumberTable:
line 13: 0
java.lang.String toString(char);
flags:
Code:
stack=1, locals=2, args_size=2
0: iload_1
1: invokestatic #6 // Method java/lang/String.valueOf:(C)Ljava/lang/String;
4: areturn
LineNumberTable:
line 16: 0
}
看着挺高端的,有时间再慢慢研究,还有另一种命令
2.javap –c ** >> **.txt
上面链接给的测试类,我们确实时常讨论String,StringBuilder,StringBuffer之间的区别,其实看字节码确实能看出一点区别,即使不懂字节码。
TestString.java
public class TestString {
public String testString(String str1, String str2){
return str1 + str2;
}
public String testStringBuffer(StringBuffer sb, String str){
return sb.append(str).toString();
}
public String testStringBuilder(StringBuilder sb, String str){
return sb.append(str).toString();
}
}
编译生成字节码后,输入
javap -c TestString >> TestString.txt
生成文本如下:
Compiled from "TestString.java"
public class TestString {
public TestString();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.String testString(java.lang.String, java.lang.String);
Code:
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: aload_1
8: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
12: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn
public java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String);
Code:
0: aload_1
1: aload_2
2: invokevirtual #6 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
5: invokevirtual #7 // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
8: areturn
}
Compiled from "TestString.java"
public class TestString {
public TestString();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.String testString(java.lang.String, java.lang.String);
Code:
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: aload_1
8: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
12: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn
public java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String);
Code:
0: aload_1
1: aload_2
2: invokevirtual #6 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
5: invokevirtual #7 // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
8: areturn
public java.lang.String testStringBuilder(java.lang.StringBuilder, java.lang.String);
Code:
0: aload_1
1: aload_2
2: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
5: invokevirtual #5 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
8: areturn
}
可以看到对于定义String类型的字符做字符连接时所执行的方法要多于StringBuffer和StringBuilder,StringBuffer和StringBuilder是一样的,不过StringBuilder是非线程安全的,StringBuffer是线程安全的,所以一般推荐使用StringBuffer,以前看人用java代码测试运行时间来观察执行效率,其实这样通过字节码大体猜测感觉也是挺不错的。