分享

分析Java .class文件

 catph 2011-04-19
这章的一个例子虽然简单,但是我觉的很有一定代表性。例子如下:

1:class Act {
2:   public static void doMathForever(int m) {
3:      int i = 0;
4:     int n=4>3?1:0;
5:        for (;;) {
6:           i += 1;
7:            i *= 2;
8:       }
9:    }
10:}


我用javap -verbose Act查看,代码如下:(红色为自己加上的注解)
Compiled from "Act.java"     
因 为编译原文件不一定必须与java语言相关,可以使用其他语言来编写程序,然后将其编译为class文件,所以这里要写上Act.java而不是Act. 呵呵,想来以前为什么javac 来编译源文件时一定要加.java,而java 执行时就不需要加.java了,当时就是搞不懂,现在明白了。
class Act extends java.lang.Object
  SourceFile: "Act.java"
SourceFile属性,它提供了产生class文件的源文件的名称,它是一个可选的项,为什么说它是可选项的,因为class可以自己用UE等工具写。
  minor version: 0
  major version: 49
版本号:我用的是5.0的,出来的major version 是49,书上说1.0或1.2是45,1.4我想可能是48 吧。呵呵,还没有试过。
  Constant pool:
这个是常量池,刚看书的时候我还以为常量池放的一定是常量。错。
常量池就是该类型所用常量的一个有序集合,包括直接常量(String,integer,floating  point常量)和对其他类型、字段和方法的符号引用。
const #1 = Method #3.#12; //  java/lang/Object."<init>":()V
因为Constant pool#0是不用的,所以只能从#1开始,但不知为什么第一个是Method而不是class,我现在还不明白。
const #2 = class #13; //  Act
CONSTANT_Class是对一个类或接口的符号引用。这个是指向#13
const #3 = class #14; //  java/lang/Object
const #4 = Asciz <init>;
 这个Asciz应该表示是CONSTANT_Utf8吧,因为C ONSTANT_Utf8可以是存储四种基本信息类型:文字字符串、被定义的类和接口描述、对其他类或接口的符号引用以及属性相关的字符串。
<init>是实例的初始化方法,是实例调用方法前必须要<init>的,
<clinit>是类的初始化方法。
const #5 = Asciz ()V;
此<init>的描述符,()V表示<init>没有带参数,返回的是void型的。
书上介绍:
()I  int getSize()  
() Ljava/lang/String      String toString()

const #6 = Asciz Code;
Code在所有不是抽象或者本地方法的method_info信息中,都存在一个Code_attribute表。
但是我试一下在抽象的方法中同样也有code的啊,不懂中。
const #7 = Asciz LineNumberTable;
LineNumberTable属性建立了方法字节码流偏移量和源代码行号之间的映射关系。关于这一点,我在下面详细谈到。
const #8 = Asciz doMathForever;
#8 字段名和方法名以简单名称出现在常量池的入口中,存的时候存简单名字,调用的时候要加 上全限定名
const #9 = Asciz (I)V;
doMathForover的描述符,参数是int类型,返回值是void类型
const #10 = Asciz SourceFile;
const #11 = Asciz Act.java;
const #12 = NameAndType #4:#5;//  "<init>":()V
NameAndType指向字段或者方法的符号引用的一部分。为什么没有指向#8,#9呢?不懂中。
const #13 = Asciz Act;
const #14 = Asciz java/lang/Object;

#13,#14 CONSTANT_Utf8_info 表的入口,容纳了 类/接口全限定名等信息。用“/”代替“.”。在class文件的this_class字段是 对常量池的一个引用,指向了常量池中CONSTANT_ClASS_info表,该表由两项组成,即标签和name_index。在这个例子 里,this_class的值为2,也就是常量池里的第二项,这项标签是class,name_index是13,即指向常量池的第13项。第13项里就 有当前类的全限定名。
{
Act();
  Code:
   Stack=1, Locals=1, Args_size=1
需要的栈为1个,只是this的存取;本地变量为1个,也是this,方法的参数是1个,也是this传入。
   0: aload_0
从局部变量0中装载引用类型。
   1: invokespecial #1; //Method java/lang/Object."<init>":()V
调用Object的<init>方法,因为每个类都是继承Object,所以实例时都要调用Object的<init>方法。
   4: return
  LineNumberTable:
   line 1: 0

public static void doMathForever(int);
  Code:
   Stack=2, Locals=3, Args_size=1
   0: iconst_0 
将i 压入栈
   1: istore_1 
放i
   2: iconst_1
同上
   3: istore_2
   4: iinc 1, 1  i++
  7   iload_1 从局部变量1中装载int类型值。
   8: iconst_2
   9: imul
   10: istore_1
   11: goto 4
  LineNumberTable:
   line 3: 0  源代码第3行对应Code中的0偏移量。
   line 4: 2
   line 6: 4
   line 7: 7
   line 8: 11

}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多