这篇文章主要介绍“java虚拟机的类加载机制介绍”,在日常操作中,相信很多人在java虚拟机的类加载机制介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java虚拟机的类加载机制介绍”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
10年积累的成都做网站、网站设计经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有南昌县免费网站建设让你可以放心的选择与我们合作。
类加载的时机
说到类加载的时机,就不得不提类加载的生命周期了,加载——验证——准备——解析——初始化——使用——卸载。七个阶段。书中说解析和初始化的位置可以互换,是为了支持java语言的动态绑定导致的。这点我暂时不知道,不做研究先。
不过我们一起来探讨下类加载什么情况下会立即触发初始化呢。
java虚拟机规范中明确规定了五种情况必须立即对类进行初始化:
遇到new、getstatic、putstatic或者invokestatic 这4条字节码指令时,如果类没有初始化,则会先触发类进行初始化。这4条指令对应最常见的java代码场景为:使用new关键字实例化对象的时候、读取或者设置一个类的静态变量(static final修饰的变量不算,因为在编译期就把该变量放入常量池中了)、调用一个类的静态方法。
使用java.lang.reflect包的方法对类进行放射调用时,如果没有初始化,会优先初始化
初始化一个类的时候,如果发现其父类还没有初始化,会优先初始化其父类
当虚拟机启动时,用户指定一个要执行的主类(main()方法的类),会优先初始化主类
如果java.lang.invoke.MethodHandle实例最后解析的结果REF_getstatic、REF_putstatic、ERF_invokestatic的方法句柄,且这个方法的句柄所对应的类没有初始化,则会优先初始化。
以上的5中场景成为对一个类的主动引用,除此之外,所以引用类的方式都不会触发初始化,成为被动引用。
下面看看代码:
package chapter.Seven;
class SuperClass {
static{
System.out.println("SuperClass init");
}
public static int value=123;
public static final String NAME="QuellanAn";
}
class SubClass extends SuperClass {
static{
System.out.println("SubClass init");
}
}
public class NotInitialzation {
public static void main(String[] args){
System.out.println(SubClass.value);
}
}
main方法中调用“SubClass.value”,value是SuperClass的静态变量。所以触发了上面第一点,所以SuperClass类会被初始化。虽然是通过SubClass调用的,但是SubClass类没有触发上面5点的任何一点,所以不会进行初始化。
结果:
SuperClass init123
在看一个,就改下main()方法,其他都不不变。
public class NotInitialzation { public static void main(String[] args){ System.out.println(SubClass.NAME); }}
同样根据上面第一点,可以发现,NAME是静态常量,在编译期(形成class文件的时候)就已经存在常量池中了。所以SuperClass也是不会初始化的。
结果:
QuellanAn
上面的例子可以很好的看出什么时候对这个类初始化了什么时候没有。有且只有上面那5中情况才会对类型进行初始化。
另外说一点,当一个类在初始化时,要求其父类全部都已经初始化了,但是在接口初始化时,并不要求父接口全部初始化,只需要在正真用到哪个父接口就初始化那个。
类加载的过程
类加载的过程分为7个阶段,但重要的前面加载——验证——准备——解析——初始化前面5个。下面来依次的说明下。
加载
在加载阶段,虚拟机需要完成以下3件事:
1. 通过一个类的全限定名来获取定义此类的二进制字节流。(全限定名:第一次听到这个词有点摸不着头脑,网上查了一下,才知道是有点绝对路径的意思,比如
Java类包的定名:com.linux.struct.sort.bubblesort,从最原始最上层的地方援引到具体的对象,这就是全限定名了)
2.将二进制字节流中所代表的的静态存储结构转化为方法区运行时结构。
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个的类的各个数据的访问入口。
验证
验证是连接阶段的第一步,验证的目的主要是为了确保class文件转换成的二进制文件流中包含的信息符合当前虚拟机的要求。并且不会危害到虚拟机的安全。
验证阶段主要完成4个阶段的验证工作:文件格式检验、元数据校验、字节码校验、符号引用校验。
准备
准备阶段,是正式为类的变量分配内存空间并设置类变量初始值的阶段。这些变量所使用内存都将在方法区中分配。需要注意的是:这个阶段今次进行内存分配的进包含类变量,而不包含实例变量。实例变量将在对象实例化时随着对象一起分配到java堆中。并且这里说的初始值“通常情况”下是数据类型的零值,比如:
public static int value=123;
在value准备阶段过后的初始值为0,而不是123.value值在初始化的时候才会被赋值成123.因为把value赋值为123的putstatic指令在初始化后才执行。
解析
解析阶段是虚拟机将常量池内的符号引用替换成直接引用的过程。
初始化
初始化阶段,执行类构造器
到此,关于“java虚拟机的类加载机制介绍”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!