`

HelloWorld.class 文件的解读---方法解读

    博客分类:
  • JVM
阅读更多

前面两个例子,一个简单的替换了二进制的编码一个通过理解class的文件格式,可以增加输出的内容,都非常简单,但是实际可能用到的不会这么简单,更多的是对方法的操作,比如spring aop的实现方式有两种动态代理和字节码增强,其中字节码增强便可以通过修改class的二进制文件完成,另外对性能分析、调试跟踪和日志记录,也可以通过这种方式简单的实现,当然在现实中我们不会去真正的操作二进制码,我们一般通过第三方的库文件,比如:asm、 cglib、 serp、 和bcel等;但是他们的本质还是去操作二进制码;前面在分析helloworld.class 的时候,还剩下两块内容当时没有讨论(其实是一样的结构),这里我们先讨论这两块内容:

第一块: 第39点后面剩下的29个字节如下(请先回顾39点的内容):

 

 

0000014fh: 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 ; ........*?.?..
0000015fh: 01 00 0A 00 00 00 06 00 01 00 00 00 01          ; .............

 Code_attribute 的定义:

 

 

 

Code_attribute {          
        u2 attribute_name_index;  
         u4 attribute_length;  
         u2 max_stack;  
         u2 max_locals;  
         u4 code_length;  
         u1 code[code_length];  
         u2 exception_table_length;  
         {       u2 start_pc;  
                u2 end_pc;  
                u2 handler_pc;  
                u2 catch_type;  
         }       exception_table[exception_table_length];  
         u2 attributes_count;  
         attribute_info attributes[attributes_count];  
    } 

 

 

 按照Code_attribute 的定义分析29个字符:

(1)、0X 00 01 表示max_stack;表示该方法执行的时候操作数栈最大的长度;这里表示操作数栈的长度为1;

(2)、0X 00 01表示 max_locals;表示方法局部变量所需要的空间的长度,

(3)、0X 00 00 00 05 表示code_length=5;即后面的5个字节为code的内容;

(4)、0X 2A B7 00 01 B1 :5个字节表示的便是code 的内容;

 

 

  • 0X 2A :aload_0 表示将第一个引用类型本地变量推送至栈顶  
  • 0X B7 :invokespecial   调用超类方法,后面的0X 00 01,查看1号常量池 表示void init();所有表示调用超类的init方法
  • 0X B1 return 返回void;

(5)、0X 00 00 :表示exception_table_length=0;也就是说没有异常处理;

(6)、0X 00 01 :表示attributes_count=1;接下来有一个attribute_info 的结构:

 

先复习一下attribute_info 的结构定义:

 

 

attribute_info {          
 u2 attribute_name_index;  
 u4 attribute_length;  
 u1 info[attribute_length];  
    }

 

     1)、0X 00 0A :表示  attribute_name_index,查看10号常量池,为LineNumberTable ;查看LineNumberTable  属性的定义:

 

 

lineNumberTable_attribute{
U2                         attribute_name_index;
U4                         attribute_length;
U2                          line_number_table_length
line_number_info   line_number_table 
}

line_number_info  的定义:

line_number_info  {
U2    start_pc;
U2    line_number;
}

 

   2)、0X 00 00 00 06 :表示attribute_length=6,

   3)、0X 00 01 :表示line_number_table_length=1,即后面有一个line_number_info 结构

       3.1)、0X 00 00 表示 start_pc; 新行开始时,代码数组的偏移量,该偏移量从代码数组的起始位置开始;

       3.2)、0X 00 01 表示 line_number=1

 

LineNumberTable  中包含了一些调试信息,不做讨论;
到这里第一块结构就ok了;

 

第二块: 第41点后面剩下的37个字节如下(请先回顾41点的内容):这个结构和上面的第一块内容基本一致;

 

0000017ah: 00 02 00 01 00 00 00 09 B2 00 02 12 03 B6 00 04 ; ........?...?.
0000018ah: B1 00 00 00 01 00 0A 00 00 00 0A 00 02 00 00 00 ; ?..............
0000019ah: 03 00 08 00 04                                  ; .....

 

 

(1)、0X 00 02 表示max_stack;表示该方法执行的时候操作数栈最大的长度;这里表示操作数栈的长度为2;

(2)、0X 00 01 表示 max_locals;表示方法局部变量所需要的空间的长度

(3)、0X 00 00 00 09 表示code_length=5;即后面的9个字节为code的内容;

(4)、 B2 00 02 12 03 B6 00 04 B1 :9个字节表示的便是code 的内容;

      该code[] 包含的实现该方法的JVM 的实际的字节,

 

  • 0X B2 :getstatic 指令:表示获取指定类的静态域,并将其值压入栈顶,后面的0X 00 02 ;查看2号常量池,即将out(sysytem.out)压入栈
  • 0X 12 :ldc:表示将一个常量池压入操作栈,后面的0X 03 便是这个操作数,查看第3号常量池,为hello world,我们要输出的内容;
  • 0X B6 : invokevirtual,调用实例方法,后面的0X 00 04 ,查看4号常量池 表示java/io/PrintStream的println方法,这个指令弹出两个操作数,即是调用 out.print("hello world");
  • 0X B1 : return ;返回void

 

(5)、0X 00 00 :表示exception_table_length=0;也就是说没有异常处理;

(6)、0X 00 01 :表示attributes_count=1;接下来有一个attribute_info 的结构:

   1)、0X 00 0A :表示  attribute_name_index,查看10号常量池,为LineNumberTable ;

             查 看LineNumberTable  属性的定义:

 

   2)、0X 00 00 00 0A :表示attribute_length=10,

   3)、0X 00 02 :表示line_number_table_length=2,即后面有一个line_number_info 结构

       3.1)、0X 00 00 表示 start_pc;新行开始时,代码数组的偏移量,该偏移量从代码数组的起始位置开始;

       3.2)、0X 00 03 表示 line_number=3

 

       3.3)、0X 00 08 表示 start_pc;新行开始时,代码数组的偏移量,该偏移量从代码数组的起始位置开始;

       3.4)、0X 00 04 表示 line_number=4

LineNumberTable  中包含了一些调试信息,不做讨论;

至此 整个helloworld的class 文件全部分析好了,

另外:

1、文章中提高的指令集参照 http://thinkinmylife.iteye.com/blog/443900

2、对在class 复合数据结构中的 9中属性没有做详细的介绍,只是对用到的code_attribute,sourcefile_attribute,linenumbertable_attribute ,有一个简单的说明,其他还有sythetic、localvariabletable、innerclass、exception、deprecated、constantvalue几种;

 

 

 

本站支持 pay for your wishes

3
1
分享到:
评论
6 楼 小羊fc 2012-10-11  
大神!
5 楼 xm_king 2011-07-11  
希望楼主加油
4 楼 xm_king 2011-07-11  
Spring 实现AOP的两种方式的第一种动态代理看过Spring的源码,基本明白了。字节码增强没看过,两种方式比较的话,显然是字节码增强技术的效率更高。
3 楼 xm_king 2011-07-11  
楼主很耐心,很认真,很有钻研精神。很有做黑客的潜质
2 楼 诸葛不亮 2011-07-11  
TheNewBeginning 写道
虽然还不理解,先支持下。

说明这个表达能力亟待提高啊。。哈哈!
1 楼 TheNewBeginning 2011-07-10  
虽然还不理解,先支持下。

相关推荐

    Hello World the WebWork way

    public class HelloWorld implements Action { private String message; public String execute() { message = "Hello, World!\n"; message += "The time is:\n"; message += System.currentTimeMillis(); ...

    生成JAR包的方法(打包后运行好像不快)

    10. **示例**:创建名为`Hello.jar`的JAR包,包含`HelloWorld.class`类,并使用清单文件`manifest.mf`: ```sh jar cvfm Hello.jar manifest.mf HelloWorld.class ``` 11. **清单文件示例**:清单文件通常包含...

    LINUX下JAVA環境配置.pdf

    - **意义**:编译Java源代码文件,如果一切正常,会生成`HelloWorld.class`文件。 ##### 5.4 运行:`java HelloWorld` - **命令**:在终端中输入`java HelloWorld`。 - **意义**:运行编译后的Java程序,输出`...

    class文件解析案例

    例如,一个简单的`HelloWorld`类,通过反编译工具(如javap)查看其字节码,可以观察到`main`方法的执行流程。 4. **样例数据分析**: 提供的jvm.docx文件可能包含更详细的案例分析,比如如何解析特定的class文件...

    Java学习总结.pdf

    Java源代码文件通常以.java为扩展名,比如HelloWorld.java,里面定义了public class以及main方法作为程序的入口。 ```java public class HelloWorld { public static void main(String args[]) { System.out....

    java入门之java基础语法.docx

    - 如果编译成功,则会在同一目录下生成`HelloWorld.class`文件。 - **运行程序**: - 输入`java HelloWorld`运行程序。 - 屏幕上将显示`Hello World`。 #### 五、Java基础语法要点 - **大小写敏感**:Java区分...

    JDK开发工具命令集合

    示例:javac HelloWorld.java ``` - **常见选项** - `-g`:生成完整的调试信息。 - `-g:none`:不生成任何调试信息。 - `-g:{lines,vars,source}`:仅生成特定类型的调试信息。 - `-nowarn`:忽略警告信息。...

    合工大Java实验报告.doc

    例如,`javac HelloWorld.java`会生成`HelloWorld.class`。然后,通过`java`命令运行程序,如`java HelloWorld`。实验还涉及了多包管理,创建了位于`a`包下的`A`类和`b`包下的`B`类,`B`类中实例化了`A`类的对象。 ...

    京东T5级大牛带你解读Spring核心源码——1小时手写SpringMVC~

    <property name="message" value="Hello World!" /> ``` - **步骤二:定义前端控制器** 创建一个`DispatcherServlet`类,该类负责处理HTTP请求,并调用相应的控制器处理请求。 ```java public class ...

    JavaSE学习笔记.docx

    - **实现第一个HelloWorld** - 编写Java源代码并保存为`.java`文件。 - 使用`javac 文件名.java`命令来编译源代码。 - 使用`java 文件名`命令来运行编译后的程序。 - 注意事项: - 类名和文件名必须一致。 - 源...

    axis2发布web service

    然后,在 `src` 目录下创建一个 Java 类 `helloWorld`,其中包含一个公共方法 `sayHello`,该方法接受一个字符串参数 `name` 并返回一条问候消息。 ```java public class helloWorld { public String sayHello...

    JAVA运行环境的安装[收集].pdf

    - 编译Java程序:`javac HelloWorld.java`,这将生成一个`HelloWorld.class`字节码文件。 - 运行Java程序:`java HelloWorld`,这将在控制台打印出"hello,java!"。 6. **Applet程序** - Applet是能在网页中运行...

    AE开发学习PPT

    - 第一个ArcEngine程序:通过编写简单的“Hello World”程序,理解ArcEngine应用程序的基本结构。 2. **地图控件的应用开发基础** (2.地图控件的应用开发基础.ppt) - 地图对象模型:了解地图对象模型的层次结构,...

    创建简单的WEB应用-maven-Tomcat版.doc

    response.getWriter().println("Hello, World!"); } } ``` 记得在`web.xml`中注册这个Servlet: ```xml <servlet-name>HelloWorldServlet</servlet-name> <servlet-class>...

    中期开发平台说明文档-数据及业务层

    * Class:每个 Java 文件应该包含类定义,例如:public class HelloWorld { ... }。 * Class Fields:每个 Java 文件应该包含类字段定义,例如:private int count;。 DEMO 简介 在中期开发平台中,我们提供了一个...

    JAVA环境变量设置源码范例和详细说明(由浅入深,深度解读在资料后半部分).docx

    String value = "Hello, World!"; System.out.println("Before setting: " + System.getenv(key)); try { ProcessBuilder builder = new ProcessBuilder(); Map, String> env = builder.environment(); env....

    28.接口基本定义版.pdf

    public static final String MSG = "Hello World."; public abstract void print(); } ``` 2. 接口的使用形式 当一个接口定义完成之后,需要遵循如下的步骤进行接口的使用: * 接口一定要定义子类,子类利用...

Global site tag (gtag.js) - Google Analytics