深入理解java虚拟机之类文件结构以及加载

  我们都知道,java是一种平台无关的语言。java代码通过java编译器(如javac等),将.java文件编译成字节码,也就是.class文件。字节码是运行在jvm虚拟机之上的。而不同的平台则 有不同的虚拟机映射规则。因此,我们从虚拟机上面一层来看,java是平台无关的。write once ,写的java程序,只要在装了jre的电脑,或者任何设备中,都可以运行,也就是run anywhere.

  下面主要介绍一下从深入理解Java虚拟机中学习到的类文件结构,也就是class文件规范。

class文件,按照以下的数据项,不论是顺序还是数量甚至数据存储的字节序(大端法)都是严格规定的,哪个字节代表什么含义长度先后顺序都不能改变。u1 u2 u4 u8表示1 2 48个字节的无符号数,可以用来描述数字 索引引用,数量值或者按照UTF-8构成的字符串值。

类型 名称 数量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count - 1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attribute_count 1
attribute_info attributes attributes_count

针对上述结构,对于每个info,又有很多内容。详细参见深入java虚拟机把。。。。

接下来谈一下,Java虚拟机如何夹杂class文件,以及class文件被加载到虚拟机后又发生了什么?

java虚拟机的类加载机制:虚拟机将描述类的数据从class文件中加载到内存,然后对数据进行校验,转换解析,初始化,最终形成可以被虚拟机直接利用的java类型的过程。

java加载链接和初始化,都是在程序运行时完成的。

类的生命周期:加载--验证--准备--解析--初始化--使用--卸载。

在什么情况下会触发初始化?

1.new(创建实例指令) getstatic putstatic invokestatic(访问类字段,或者成为类变量):使用new实例化对象时,读取或者设置一个静态字段(被final修饰已在编译期把结果放入常量池的静态字段除外)以及调用静态方法时

2.使用java.lang.reflect包对类进行反射调用。如果类没有初始化,首先触发初始化。

3.初始化一个类时,如果父类还没有被初始化,那么先要触发其父类的初始化。

4.虚拟机启动时,用户需要指定一个需要执行的主类(就是main()的那个类) 虚拟机会首先初始化这个主类。

5.jdk1.7以上,动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的结果REF_getstatic,REF_putstatic,REF_invokestatic的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则必须触发初始化。

虚拟机规范中指明:有且只有 以上行为才会初始化,称为主动引用。除此之外的任何引用类的方法,都不会触发初始化,称之为被动引用。

其实根据以上五条规则,就可以知道类的加载顺序了。

原文地址:https://www.cnblogs.com/CongLollipop/p/6666410.html