您的位置:首页 > 编程语言 > Java开发

Java编译原理

2016-02-22 11:50 459 查看
代码Test.java

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: