当前位置:首页 > 开发 > 编程语言 > Java > 正文

Java 字节码之解析一

发表于: 2011-12-01   作者:周凡杨   来源:转载   浏览:
摘要:     一: Java 字节代码的组织形式   类文件 {     OxCAFEBABE ,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域信息数组,方法个数,方法信息数组,属性个数,属性信息数组 } &nbs

 

 

一: 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   <init>;
const #16 = Asciz   ()V;
const #17 = Asciz   Code;
const #18 = Method       #3.#19;   //  java/lang/Object."<init>":()V
const #19 = NameAndType    #15:#16;//  "<init>":()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."<init>":()V
   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; //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:
   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 :签名如<init>jvm 调用,其他是不能够去调用它的

NameAndType :变量名的类型

Class :类

 

通过字节码,我们可以看到 Demo 继承于 java.lang.Object ,如果类中没有显式声明构造函数的话,编译器会插入一个缺省无参的构造函数 ( 构造函数在 JVM 级别是显示成 <init> 的普通函数 )

 

 

三: 检测代码的效率问题

 

学习 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."<init>":()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."<init>":(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:      areturn
 
}
 
 

从上面编译后的字节码信息可以看出来,方法testString 调用了五个方法:new invokestatic invokespecial 和两个invokevirtual ; testStringBuffer 方法只调用了两个invokevirtual 方法。第一个方法比第二个方法多做了好多工作,其效率当然是要低的。而且我们从java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

可以看出来其实对于String 字符串合并,内部还是转化为StringBuilder 的方法调用,这是因为String 是长度不可变的,所以不如直接采用StringBuilder (与StringBuffer 长度都是可变的,只不过前者是非线程安全,后者是线程安全)进行字符串合并。
 

 

 

Java 字节码之解析一

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
相信学java的人都对new Object();创建对象都很熟悉,但想要真正了解原理就没那么容易!以以下例子为
学习Java字节码有助于理解Java内存结构,加深对JVM的理解。 首先需要知道JVM内存由 堆、栈、方法区、
很多时候我们在编写Java代码时,判断和猜测代码问题时主要是通过运行结果来得到答案,本博文主要是
http://asm.ow2.org/index.html (asm官方网址) http://download.forge.objectweb.org/ (asm下载的父
Java是一门设计为运行于虚拟机之上的编程语言,因此它需要一次编译,处处运行(当然也是一次编写,处
你知道如何操作JAVA字节码文件吗,这里将介绍与操作Java字节码有关的基本知识和操作Java字节码的方
这篇文章能让你对Java字节码有个了解,这可以帮你成为一个更好的程序员。就像C或C++编译器将源码编
实现语言与操作系统的无关性基础仍然是虚拟机和字节码储存格式,jvm不与java及其他任何语言绑定,只
上一篇BLOG中总结了对Java内存管理的认识http://japi.iteye.com/blog/261626 还http://japi.iteye.co
痛痛快快来分析一下java字节码文件: 根据j2se7 Virtual Machine Specific:http://docs.oracle.com/
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号