JVM:四、类文件结构解析

本文详细解析了虚拟机如何通过字节码实现语言无关性,以及类文件的具体结构,包括常量池、访问标志、字段表、方法表等组成部分。深入探讨了字节码指令的种类及功能,如加载存储、运算、类型转换等,并介绍了虚拟机如何通过管程实现同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

虚拟机的语言无关性靠的是字节码来实现的,虚拟机不和包括Java在内的任何语言绑定,只和“Class文件”绑定,Java,Jruby,Groovy程序经过各自的编译器形成字节码文件(.class)或叫做类文件。虚拟机处理类文件。类文件结构主要包括以下几部分:Class文件版本 + 常量池 + 访问标志 + 类索引父类索引接口索引集合 + 字段表 + 方法表 + 属性表

1. 类文件结构

常量池

可以理解为Class的资源仓库,占用空间最大的数据项目之一,是一个表类型数据项目,一个常量就是一个表,一共有21个类型的表。

它与很多的结构都有关联,例如字段表和方法表都会用到常量池,算是很复杂的一个部分。主要有字面量和符号引用组成。字面量就是文本字符串和final常量值,符号引用包含三类:类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。

在这列出21个类型的表的几种:整形字面量,字符串字面量,类和接口的符号引用,字段的符号引用,类中方法的符号引用,接口中方法的符号引用,表示方法类型,表示方法句柄。。。

访问标志

用于标识这个类或接口的访问信息,例如这个Class是接口还是类,是否定义为public类型,是否定义为abstract类型,是否声明为final。

类索引,父类索引,接口索引集合

确定类的继承关系。其中类索引用于确定这个类的全限定名。由于类只可以单继承,接口可以多继承,所以父类索引只有一个,接口索引是集合;由于所有的类都是继承自Object,所以除了Object外父类索引不能为0。(全限定名这些名称都存在常量池里,更具体一点是常量池里的类和接口符号引用表)

字段表集合

接口或类中声明的变量,可以是类级变量可以是实例变量,但不包括方法内的局部变量。

字段表一般有访问标志(access_logs),名称索引(name_index),描述符索引(descriptor_index),属性表集合(attributes)几个项目,都是一个u2类型的数据,其中name_index表示字段的简单名称,descriptor_index表示描述符。

access_logs和类中的访问标志作用类似。可以设置的标志位有:

字段的作用域(private,public,protected),实例变量还是类变量(有无static),可变性(final),并发可见性(volatile,是否强制从主内存读写),可否序列化(transient)。

以上各个修饰符都是布尔值,而字段叫什么,是什么类型是无法固定的,只可以通过name_index和descriptor_index两个项目引用常量池中的常量来表述。

例如:private volatile Integer a = 23;那么private,volatile这些属性都会存在字段表里,而 'a' 这个字段名需要地址从常量池里取

方法表集合

方法表结构和字段表接口类似,依次包括访问标志(access_logs),名称索引(name_index),描述符索引(descriptor_index),属性表集合(attributes)。

因为volatile和transient不可以用来修饰方法,所以方法表的访问标志中没有了ACC_VOLATILE和ACC_TRANSIENT。

但是也会比字段表多一些访问标志位,例如ACC_ABSTRACT,ACC_SYNCHRONIZED。、

如果父类方法没有被子类重写,那么子类中不会有父类的方法信息。

一般来说,编译器也会自动添加一些方法,例如类初始化的类构造器<cliint>方法和实例构造器<init>方法

属性表集合

会存一些方法内部的代码(Code)供方法表调用,final关键字定义的常量(ConstantValue)字段表调用等等。

 

2. 字节码指令

在此列出9种类型的字节码指令

加载和存储指令:iload,istore,bipush

运算指令:iadd,isub,imul

类型转换指令

对象创建和访问指令:

  • new,创建类的实例
  • newarray,创建数组
  • getfield,访问实例字段
  • putfield,更改实例字段
  • getstatic,访问static字段,或称为类变量
  • putstatic,更改类变量

擦作数栈指令:pop,dup

控制转移指令:ifeq,iflt,goto

方法调用和返回指令:

  • invokevirtual,调用对象实例方法
  • invokeinterface,调用接口方法
  • invokespecial,调用特殊方法,例如实例初始化方法
  • invokestatic,调用类方法
  • invokedynamic,用于运行时动态解析出调用点限定符所引用的方法

异常处理指令:athrow

同步指令:不管是支持方法级的同步还是方法内部一段指令序列的同步,都是使用管程(Monitor)来实现的。

    方法的同步是隐式的,什么意思呢?就是不需要字节码指令来控制,虚拟机会从方法表的ACC_SYNCHRONIZED访问标志中获取方法是否被设置了,如果设置了就要获取管程才可以执行方法。

    同步一段序列指令一般使用synchronized语句块来实现。虚拟机通过monitorenter和monitorexit两条指令来支持synchronized语义。

 

 

 

摘自《深入理解JVM虚拟机》

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值