会计考友 发表于 2012-8-4 12:44:44

Java字节码深入解析

一: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;   //Demo
const #2 = Asciz   Demo;
const #3 = class      #4;   //java/lang/Object
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; //hello world
const #14 = Asciz   hello world;
const #15 = Asciz   ;
const #16 = Asciz   ()V;
const #17 = Asciz   Code;
const #18 = Method       #3.#19;   //java/lang/Object."":()V
const #19 = NameAndType    #15:#16;//"":()V
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;//java/lang/System.out:Ljava/io/PrintStream;
const #26 = class    #27; //java/lang/System
const #27 = Asciz   java/lang/System;
const #28 = NameAndType    #29:#30;//out:Ljava/io/PrintStream;
const #29 = Asciz   out;
const #30 = Asciz   Ljava/io/PrintStream;;
const #31 = String#32; //this is method1...
const #32 = Asciz   this is method1...;
const #33 = Method       #34.#36;//java/io/PrintStream.println:(Ljava/lang/String;)V
const #34 = class    #35; //java/io/PrintStream
const #35 = Asciz   java/io/PrintStream;
const #36 = NameAndType    #37:#38;//println:(Ljava/lang/String;)V
const #37 = Asciz   println;
const #38 = Asciz   (Ljava/lang/String;)V;
const #39 = Asciz   sayHello2;
const #40 = String#41; //this is method2...
const #41 = Asciz   this is method2...;
const #42 = Asciz   sayHello3;
const #43 = String#44; //this is method3...
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; //Method java/lang/Object."

会计考友 发表于 2012-8-4 12:44:45

Java字节码深入解析

":()V
   4:      return
LineNumberTable:
   line 2: 0
LocalVariableTable:
   StartLengthSlotName   Signature
   0      5      0    this       LDemo;</p>public void sayHello3();
Code:
   Stack=2, Locals=1, Args_size=1
   0:      getstatic   #25; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:      ldc   #43; //String this is method3...
   5:      invokevirtual#33; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:      return
LineNumberTable:
   line 17: 0
   line 18: 8
LocalVariableTable:
   StartLengthSlotName   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; //Method java/lang/Object."":()V
   4:      return
public java.lang.String testString(java.lang.String, java.lang.String);
Code:
   0:      new #16; //class java/lang/StringBuilder
   3:      dup
   4:      aload_1
   5:      invokestatic    #18; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   8:      invokespecial#24; //Method java/lang/StringBuilder."":(Ljava/lang/String;)V
   11:   aload_2
   12:    invokevirtual#27; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   15:    invokevirtual#31; //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#40; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
   5:      invokevirtual#45; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
   8:      areturnwww.ExamW.CoM
}

会计考友 发表于 2012-8-4 12:44:46

Java字节码深入解析

  从上面编译后的字节码信息可以看出来,方法testString 调用了五个方法:new 、invokestatic 、invokespecial 和两个invokevirtual ; 而testStringBuffer 方法只调用了两个invokevirtual 方法。第一个方法比第二个方法多做了好多工作,其效率当然是要低的。而且我们从java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</p>  可以看出来其实对于String字符串合并,内部还是转化为StringBuilder的方法调用,这是因为String是长度不可变的,所以不如直接采用StringBuilder(与StringBuffer 长度都是可变的,只不过前者是非线程安全,后者是线程安全)进行字符串合并。
页: [1]
查看完整版本: Java字节码深入解析