一:Java字节代码的组织形式
类文件{
OxCAFEBABE,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域信息数组,方法个数,方法信息数组,属性个数,属性信息数组
}
二:查看方法 --- javap命令
例子:有一个Java类Demo.java
- public class Demo {
- private String str1;
- private String str2;
- private int num1;
- private int num2;
- public static final String STATIC_DATA = "hello world";
-
- private void sayHello1(){
- System.out.println("this is method1...");
- }
- private void sayHello2(){
- System.out.println("this is method2...");
- }
- public void sayHello3(){
- System.out.println("this is method3...");
- }
- }
通过jdk自带的反编译工具命令 javap 可以查看class文件的字节码信息
D:\>javap -verbose Demo >> Demo.txt
Demo.txt:
- Compiled from "Demo.java"
- public class Demo extends java.lang.Object
- SourceFile: "Demo.java"
- minor version: 0
- major version: 49
-
- Constant pool:
- const #1 = class #2;
- const #2 = Asciz Demo;
- const #3 = class #4;
- const #4 = Asciz java/lang/Object;
- const #5 = Asciz str1;
- const #6 = Asciz Ljava/lang/String;;
- const #7 = Asciz str2;
- const #8 = Asciz num1;
- const #9 = Asciz I;
- const #10 = Asciz num2;
- const #11 = Asciz STATIC_DATA;
- const #12 = Asciz ConstantValue;
- const #13 = String #14;
- const #14 = Asciz hello world;
- const #15 = Asciz ;
- const #16 = Asciz ()V;
- const #17 = Asciz Code;
- const #18 = Method #3.#19;
- const #19 = NameAndType #15:#16;
- const #20 = Asciz LineNumberTable;
- const #21 = Asciz LocalVariableTable;
- const #22 = Asciz this;
- const #23 = Asciz LDemo;;
- const #24 = Asciz sayHello1;
- const #25 = Field #26.#28;
- const #26 = class #27;
- const #27 = Asciz java/lang/System;
- const #28 = NameAndType #29:#30;
- const #29 = Asciz out;
- const #30 = Asciz Ljava/io/PrintStream;;
- const #31 = String #32;
- const #32 = Asciz this is method1...;
- const #33 = Method #34.#36;
- const #34 = class #35;
- const #35 = Asciz java/io/PrintStream;
- const #36 = NameAndType #37:#38;
- const #37 = Asciz println;
- const #38 = Asciz (Ljava/lang/String;)V;
- const #39 = Asciz sayHello2;
- const #40 = String #41;
- const #41 = Asciz this is method2...;
- const #42 = Asciz sayHello3;
- const #43 = String #44;
- const #44 = Asciz this is method3...;
- const #45 = Asciz SourceFile;
- const #46 = Asciz Demo.java;
-
- {
- public static final java.lang.String STATIC_DATA;
- Constant value: String hello world
- public Demo();
- Code:
- Stack=1, Locals=1, Args_size=1
- 0: aload_0
- 1: invokespecial #18;
- 4: return
- LineNumberTable:
- line 2: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this LDemo;
-
- public void sayHello3();
- Code:
- Stack=2, Locals=1, Args_size=1
- 0: getstatic #25;
- 3: ldc #43;
- 5: invokevirtual #33;
- 8: return
- LineNumberTable:
- line 17: 0
- line 18: 8
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 9 0 this LDemo;
- }
解析:
1.版本号 major version: 49 //java版本 jdk1.6显示的是50, jdk1.5显示的是49,jdk1.4显示的是58 , 高版本能执行低版本的class文件
2.常量池Constant pool
Method:方法
Field:字段
String:字符串
Asciz:签名如由jvm调用,其他是不能够去调用它的
NameAndType:变量名的类型
Class:类
通过字节码,我们可以看到Demo类 继承于java.lang.Object,如果类中没有显式声明构造函数的话,编译器会插入一个缺省无参的构造函数(构造函数在JVM级别是显示成的普通函数) 。
三:检测代码的效率问题
学习Java的过程中,都会了解到字符串合并时要用到StringBuffer 来代替String,那下面就来通过Java字节码来验证两种方式的效率性 。
例子:一个Java类 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();
- }
- }
-
javap –c TestString 后字节码信息:
- Compiled from "TestString.java"
- public class TestString extends java.lang.Object{
- public TestString();
- Code:
- 0: aload_0
- 1: invokespecial #8;
- 4: return
-
- public java.lang.String testString(java.lang.String, java.lang.String);
- Code:
- 0: new #16;
- 3: dup
- 4: aload_1
- 5: invokestatic #18;
- 8: invokespecial #24;
- 11: aload_2
- 12: invokevirtual #27;
- 15: invokevirtual #31;
- 18: areturn
-
- public java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String);
- Code:
- 0: aload_1
- 1: aload_2
- 2: invokevirtual #40;
- 5: invokevirtual #45;
- 8: areturn
- }
从上面编译后的字节码信息可以看出来,方法testString 调用了五个方法:new 、invokestatic 、invokespecial 和两个invokevirtual ; 而testStringBuffer 方法只调用了两个invokevirtual 方法 。第一个方法比第二个方法多做了好多工作,其效率当然是要低的 。而且我们从java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
可以看出来其实对于String字符串合并,内部还是转化为StringBuilder的方法调用,这是因为String是长度不可变的,所以不如直接采用StringBuilder(与StringBuffer 长度都是可变的,只不过前者是非线程安全,后者是线程安全)进行字符串合并 。
原文链接:http://15838341661-139-com.iteye.com/blog/1287866