【理解HostSpot虚拟机】class文件格式

转载请注明出处:http://blog.csdn.net/linxdcn/article/details/73472553


1 概述

Java编译后的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];
}
  • magic:魔数,固定为0xCAFEBABE
  • minor_version:次版本号
  • major_version:主版本号
  • constant_pool_count:常量池项个数
  • constant_pool[constant_pool_count-1]:常量池表,长度为constant_pool_count-1
  • access_flags:类或接口的访问标志
  • this_class:当前类
  • super_class:超类
  • interfaces_count:接口数量
  • interfaces[interfaces_count]:接口表
  • fields_count:字段数量
  • fields[fields_count]:字段表
  • methods_count:方法数量
  • methods[methods_count]:方法表
  • attributes_count:属性数量
  • attributes[attributes_count]:属性表

关于class文件中的各项说明,可以参考虚拟机规范或者底下参考文献的两篇文章,已经总结的非常的详细,本文对其中重要的几项作一个总结。


2 常量池

  • 常量池保存了文件中类或接口相关的一切常量:
    • 字面量:文字字符串、final变量值、基础数据类型
    • 符号引用:如类或接口的全限定名、方法或字段的简单名称和描述符

根据虚拟机规范,常量池项目类型有以下分类



JVM规范规定的常量池项目类型

规范规定的总是很抽象的,下面举几个例子就好懂。

2.1 int a = 10
类型常量池索引备注
CONSTANT_Integer110字面量:基础数据类型
2.2 String a = “test”
类型常量池索引备注
CONSTANT_String1#2符号引用
CONSTANT_Utf82test字面量:文字字符串
2.3 Date a = new Date()
类型常量池索引备注
CONSTANT_Class1#1符号引用:类全限定名
CONSTANT_Utf82Ljava/util/Date;字面量:文字字符串
2.4 Field常量

在类中定义了field 字段,并且在类的其他地方(如方法中)使用到它,这是会用到Field常量,如以下代码

Class Test {
    String name;
    public void setName(String a) {
        // 这里会使用Field常量
        name = a;  // 翻译成指令为: getfield    #5
    }
}
类型常量池索引备注
CONSTANT_Class1#2符号引用
CONSTANT_Utf82package/path/Test字面量:文字字符串
CONSTANT_Utf83name字面量:文字字符串
CONSTANT_Utf84Ljava/lang/String;字面量:文字字符串
CONSTANT_Fieldref5#1.#6符号引用
CONSTANT_NameAndType6#3.#4符号引用
2.5 Method常量

假如我们只定义了方法,但是这些方法没有在类总的其他地方被用到(如2.3中的代码),则这些方法引用信息并不会放到常量中。下面代码则可以使用到Method常量。

Class Test {
    String name;
    public String getName() {
        return name;
    }
    public do() {
        // 这里会使用Method常量
        setName("test");  // 翻译成指令为: invokevirtual    #5
    }
}
类型常量池索引备注
CONSTANT_Class1#2符号引用
CONSTANT_Utf82package/path/Test字面量:文字字符串
CONSTANT_Utf83getName字面量:文字字符串
CONSTANT_Utf84()java/lang/String;字面量:文字字符串
CONSTANT_Methodref5#1.#6符号引用
CONSTANT_NameAndType6#3.#4符号引用

3 字段表-field_info[]

首先需要说明的是,属性不仅在class文件结构中使用,在field_info和method_info中也使用。

在字段域出现的属性有ConstantValue(final常量)、Deprecated(被禁用的指示符)、Synthetic(编译器产生的指示符)。

4 方法表-method_info[]

方法域出现的属性有Code、Deprecated、Exceptions、Synthetic 。

(1)Code

Code类型的属性表(attribute_info)可以说是class文件中最为重要的部分,因为它包含的是JVM可以运行的机器码指令,JVM能够运行这个类,就是从这个属性中取出机器码的。

Code属性表包含:

  • 机器指令—-code:
  • 异常处理跳转信息—exception_table
  • Java源码行号和机器指令的对应关系—LineNumberTable属性表
  • 局部变量表描述信息—-LocalVariableTable属性表

5 一些思考

(1)常量池的CONSTANT_Fieldref和跟字段域field_info的区别?

CONSTANT_Fieldref,这只是一个字段的符号引用,通常作为字节码指令(opcode)getfield/getstatic/putfield/putstatic的操作数使用。

field_info是类中定义字段本身信息的描述,关于类加载过程中field部分的解析,以及其作为InstanceKlass类中成员属性的layout。

对于getfield/getstatic/putfield/putstatic四种与Field Reference相关的指令,在字段决议——resolve_field时,会有两者的协同使用——根据符号引用去_field中查找真正的字段。符号引用只是一个对应字段的一个字符串,符号引用经第一次解析(解析结果存入ConstantPoolCache),就会变成直接引用——field_offset。

对于CONSTANT_Methodref和方法域method_info也类似。

(2)如何防止class文件被劫持?

主要通过类加载双亲委派模型实现。

jvm首先会检查该类是否已经被加载,若没有被加载,则会委托父加载器进行装载,只有当父加载器无法加载时,才会调用自身的findClass()方法进行加载。这样避免了子加载器加载一些试图冒名顶替可信任类的不可靠类,也不会让子加载器去实现父加载器实现的加载工作。

并且jvm规定只有运行时包(同一个类加载器加载的、属于同一个包的多个类型集合),才能访问同一包内的类(和其子类)的protected成员。

(3)如何防止class文件反编译?

可以参考下这篇博客:http://blog.csdn.net/yuxiaohui78/article/details/8247096


6 参考

http://blog.csdn.net/luanlouis/article/details/39892027
http://www.cnblogs.com/iceAeterNa/p/4874197.html


转载请注明出处:http://blog.csdn.net/linxdcn/article/details/73472553

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值