深入理解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的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则必须触发初始化。
虚拟机规范中指明:有且只有 以上行为才会初始化,称为主动引用。除此之外的任何引用类的方法,都不会触发初始化,称之为被动引用。
其实根据以上五条规则,就可以知道类的加载顺序了。