Java编译原理
2016-02-22 11:50
459 查看
代码Test.java
# javac Test.java
# javap -c Test
参考:http://codemacro.com/2015/03/31/intro-java-bytecode/
*.class文件就已经是编译好的byte code文件,就像C/C++编译出来的目标文件一样,已经是各种二进制指令了。这个时候可以通过JDK中带的javap工具来反汇编,以查看对应的byte code。
JVM中每个指令只占一个字节,操作数是变长的,所以其一条完整的指令(操作码+操作数)也是变长的。上面每条指令前都有一个偏移,实际是按字节来偏移的。
从上面的byte code中,以x86汇编的角度来看会发现一些不同的东西:
局部变量竟是以索引来区分:istore_1 写第一个局部变量,istore_2写第二个局部变量,第4个局部变量则需要用操作数来指定了:istore 4
函数调用invokespecial #1竟然也是类似的索引,这里调用的是Object基类构造函数
常量字符串也是类似的索引:ldc #2
整个class文件完全可以用以下结构来描述:
ClassFile {
u4 magic; //魔数
u2 minor_version; //次版本号
u2 major_version; //主版本号
u2 constant_pool_count; //常量池大小
cp_info constant_pool[constant_pool_count-1]; //常量池
u2 access_flags; //类和接口层次的访问标志(通过|运算得到)
u2 this_class; //类索引(指向常量池中的类常量)
u2 super_class; //父类索引(指向常量池中的类常量)
u2 interfaces_count; //接口索引计数器
u2 interfaces[interfaces_count]; //接口索引集合
u2 fields_count; //字段数量计数器
field_info fields[fields_count]; //字段表集合
u2 methods_count; //方法数量计数器
method_info methods[methods_count]; //方法表集合
u2 attributes_count; //属性个数
attribute_info attributes[attributes_count]; //属性表
}
这明显已经不是以区段来分的格式了,上面提到的函数索引、常量字符串索引,都是保存在constant_pool常量池中。常量池中存储了很多信息,包括:
各种字面常量,例如字符串
类、数据成员、接口引用
常量池的索引从1开始。
Java Class文件详解 【写的极好】
常量池的索引从1开始。对于上面例子Test.java,可以使用
# javap -v Test
查看其中的常量池
代码Foo.java
# javac -g Foo.java
# javap -c -s -l -verbose Foo
public class Test { public static void main(String[] args) { int a = 0xae; int b = 0x10; int c = a + b; int d = c + 1; String s; s = "hello"; } }
# javac Test.java
# javap -c Test
参考:http://codemacro.com/2015/03/31/intro-java-bytecode/
*.class文件就已经是编译好的byte code文件,就像C/C++编译出来的目标文件一样,已经是各种二进制指令了。这个时候可以通过JDK中带的javap工具来反汇编,以查看对应的byte code。
JVM中每个指令只占一个字节,操作数是变长的,所以其一条完整的指令(操作码+操作数)也是变长的。上面每条指令前都有一个偏移,实际是按字节来偏移的。
从上面的byte code中,以x86汇编的角度来看会发现一些不同的东西:
局部变量竟是以索引来区分:istore_1 写第一个局部变量,istore_2写第二个局部变量,第4个局部变量则需要用操作数来指定了:istore 4
函数调用invokespecial #1竟然也是类似的索引,这里调用的是Object基类构造函数
常量字符串也是类似的索引:ldc #2
整个class文件完全可以用以下结构来描述:
ClassFile {
u4 magic; //魔数
u2 minor_version; //次版本号
u2 major_version; //主版本号
u2 constant_pool_count; //常量池大小
cp_info constant_pool[constant_pool_count-1]; //常量池
u2 access_flags; //类和接口层次的访问标志(通过|运算得到)
u2 this_class; //类索引(指向常量池中的类常量)
u2 super_class; //父类索引(指向常量池中的类常量)
u2 interfaces_count; //接口索引计数器
u2 interfaces[interfaces_count]; //接口索引集合
u2 fields_count; //字段数量计数器
field_info fields[fields_count]; //字段表集合
u2 methods_count; //方法数量计数器
method_info methods[methods_count]; //方法表集合
u2 attributes_count; //属性个数
attribute_info attributes[attributes_count]; //属性表
}
这明显已经不是以区段来分的格式了,上面提到的函数索引、常量字符串索引,都是保存在constant_pool常量池中。常量池中存储了很多信息,包括:
各种字面常量,例如字符串
类、数据成员、接口引用
常量池的索引从1开始。
Java Class文件详解 【写的极好】
常量池的索引从1开始。对于上面例子Test.java,可以使用
# javap -v Test
查看其中的常量池
代码Foo.java
<pre name="code" class="java">public class Foo{ private static final int MAX_COUNT=1000; private static int count=0; public int bar() throws Exception{ if(++count >= MAX_COUNT){ count=0; throw new Exception("count overflow"); } return count; }
# javac -g Foo.java
# javap -c -s -l -verbose Foo
相关文章推荐
- MyEclipse Spring 学习总结三 SpringMVC 表单处理
- Java虚拟机学习笔记
- java Ping操作
- java中的IO最全面整理
- JAVA GC---新生代、老年代
- Java 自动装箱与拆箱(Autoboxing and unboxing)
- java线程同步5种方式
- java读取word内容
- Spring properties context:property-placeholder
- WebService基于Eclipse的客户端代码生成
- JAVA日期时间处理
- JavaSE-反射
- Spring AOP不拦截从对象内部调用的方法原因
- LeetCode27RemoveElement--In Java
- Java Socket编程 标准范例(多线程)
- (1) 自定义分页<采用jsp和Java实现>
- Java基础知识
- 基于Spring框架的Shiro配置
- java基础
- java集合深度复制