用Javap反编译帮你理解Java特性
来源:网络 更新时间:2014-12-3
Java开发人员熟悉在一个循环中使用StringBuffer来代替串联String对象能获得最佳性能。然而,多数开发人员从来没有比较两种方法产生的字节代码的区别。在Java开发工具包(JDK)中有一个叫做javap的工具可以告诉你为什么这样做可以获得最佳性能。
Javap将一个类和它的方法的一些转储信息输出到标准输出。该工具不把代码反编译为java源代码,但是它会把字节代码反汇编成为由Java虚拟机规范定义的字节代码指令。
在你需要查看编译器为你或者给你做了什么的时候,或者你想要看一处代码的改动对编译后的类文件有什么影响的时候,javap相当有用。
现在以我们前面提到的StringBuffer和String作为一个例子。下面是一个专门为例子设计的类,它有两个方法,都返回一个由0到n的数字组成的String,其中n由调用者提供。两个方法唯一的区别在于一个使用String构建结果,另外一个使用StringBuffer构建结果。
publicclassJavapTip{
publicstaticvoidmain(String[]args){}
privatestaticStringwithStrings(intcount){
Strings="";
for(inti=0;i<count;i ){
s =i;
}
returns;
}
privatestaticStringwithStringBuffer(intcount){
StringBuffersb=newStringBuffer();
for(inti=0;i<count;i ){
sb.append(i);
}
returnsb.toString();
}
}
现在让我们看看对这个类使用?Cc选项运行javap的输出。-c选项告诉javap反汇编在类中遇到的字节代码。
运行方式如下:
>javap-cJavapTip
此命令的输出为:
Methodjava.lang.StringwithStrings(int)
0ldc#2
2astore_1
3iconst_0
4istore_2
5goto30
8new#3
11dup
12invokespecial#4
15aload_1
16invokevirtual#5
19iload_2
20invokevirtual#6
23invokevirtual#7
26astore_1
27iinc21
30iload_2
31iload_0
32if_icmplt8
35aload_1
36areturn
Methodjava.lang.StringwithStringBuffer(int)
0new#3
3dup
4invokespecial#4
7astore_1
8iconst_0
9istore_2
10goto22
13aload_1
14iload_2
15invokevirtual#6
18pop
19iinc21
22iload_2
23iload_0
24if_icmplt13
27aload_1
28invokevirtual#7
31areturn
如果你以前没有看过Java汇编器,那么这个输出对你来说就会比较难懂,但是你应该可以看到withString方法在每次循环的时候都新创建了一个StringBuffer实例。然后它将已有的String的当前值追加到StringBuffer上,然后追加循环的当前值。最后,它对buffer调用toString并将结果赋给现有的String引用。
withStringBuffer方法与这个方法正好相反,在每次循环的时候withStringBuffer只调用现有StringBuffer的append方法,没有创建新的对象,也没有新的String引用。
在这种情况下,我们已经知道了使用StringBuffer代替String是一种好的做法,但是如果我们不知道呢?那么javap可以帮助我们找到答案。在这里你可以看到更详细的关于String,StringBuffer的解释
你并不会经常需要一个Java反汇编器,但是当你需要的时候,知道你自己的机器已经有一个并且用法相当简单的反汇编器当然是一件好事。如果你感兴趣,看书看看javap的其它选项——或许你会发现在你的环境中需要的特性。