前面两个例子,一个简单的替换了二进制的编码,一个通过理解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
相关推荐
public class HelloWorld implements Action { private String message; public String execute() { message = "Hello, World!\n"; message += "The time is:\n"; message += System.currentTimeMillis(); ...
10. **示例**:创建名为`Hello.jar`的JAR包,包含`HelloWorld.class`类,并使用清单文件`manifest.mf`: ```sh jar cvfm Hello.jar manifest.mf HelloWorld.class ``` 11. **清单文件示例**:清单文件通常包含...
- **意义**:编译Java源代码文件,如果一切正常,会生成`HelloWorld.class`文件。 ##### 5.4 运行:`java HelloWorld` - **命令**:在终端中输入`java HelloWorld`。 - **意义**:运行编译后的Java程序,输出`...
例如,一个简单的`HelloWorld`类,通过反编译工具(如javap)查看其字节码,可以观察到`main`方法的执行流程。 4. **样例数据分析**: 提供的jvm.docx文件可能包含更详细的案例分析,比如如何解析特定的class文件...
Java源代码文件通常以.java为扩展名,比如HelloWorld.java,里面定义了public class以及main方法作为程序的入口。 ```java public class HelloWorld { public static void main(String args[]) { System.out....
- 如果编译成功,则会在同一目录下生成`HelloWorld.class`文件。 - **运行程序**: - 输入`java HelloWorld`运行程序。 - 屏幕上将显示`Hello World`。 #### 五、Java基础语法要点 - **大小写敏感**:Java区分...
示例:javac HelloWorld.java ``` - **常见选项** - `-g`:生成完整的调试信息。 - `-g:none`:不生成任何调试信息。 - `-g:{lines,vars,source}`:仅生成特定类型的调试信息。 - `-nowarn`:忽略警告信息。...
例如,`javac HelloWorld.java`会生成`HelloWorld.class`。然后,通过`java`命令运行程序,如`java HelloWorld`。实验还涉及了多包管理,创建了位于`a`包下的`A`类和`b`包下的`B`类,`B`类中实例化了`A`类的对象。 ...
<property name="message" value="Hello World!" /> ``` - **步骤二:定义前端控制器** 创建一个`DispatcherServlet`类,该类负责处理HTTP请求,并调用相应的控制器处理请求。 ```java public class ...
- **实现第一个HelloWorld** - 编写Java源代码并保存为`.java`文件。 - 使用`javac 文件名.java`命令来编译源代码。 - 使用`java 文件名`命令来运行编译后的程序。 - 注意事项: - 类名和文件名必须一致。 - 源...
然后,在 `src` 目录下创建一个 Java 类 `helloWorld`,其中包含一个公共方法 `sayHello`,该方法接受一个字符串参数 `name` 并返回一条问候消息。 ```java public class helloWorld { public String sayHello...
- 编译Java程序:`javac HelloWorld.java`,这将生成一个`HelloWorld.class`字节码文件。 - 运行Java程序:`java HelloWorld`,这将在控制台打印出"hello,java!"。 6. **Applet程序** - Applet是能在网页中运行...
void HelloWorld() { Console.WriteLine("Hello, World!"); } ``` #### 29. 面向对象的特性 - **封装**。 - **继承**。 - **多态**。 #### 30. 实现接口的步骤 - **定义接口**。 - **实现接口**。 - **使用...
- 第一个ArcEngine程序:通过编写简单的“Hello World”程序,理解ArcEngine应用程序的基本结构。 2. **地图控件的应用开发基础** (2.地图控件的应用开发基础.ppt) - 地图对象模型:了解地图对象模型的层次结构,...
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 简介 在中期开发平台中,我们提供了一个...
String value = "Hello, World!"; System.out.println("Before setting: " + System.getenv(key)); try { ProcessBuilder builder = new ProcessBuilder(); Map, String> env = builder.environment(); env....
public static final String MSG = "Hello World."; public abstract void print(); } ``` 2. 接口的使用形式 当一个接口定义完成之后,需要遵循如下的步骤进行接口的使用: * 接口一定要定义子类,子类利用...