Java程序经过编译后形成*.class文件。通过类加载器将字节码(*.class)加载入JVM的内存中。JVM将类加载过程分为 加载,连接,初始化三个阶段。其中连接阶段又可分为验证,准备,解析三个阶段。
类加载是通过ClassLoader及其子类完成的。如下图:
1,Bootstrap ClassLoader启动类加载器。
负责加载$JAVA_HOME中jre/lib里面所有的class文件和能被虚拟机识别的类库。他是由C++实现的,不是ClassLoader子类,无法被Java程序直接引用。
2,Extension ClassLoader扩展类加载器。
负责加载Java平台中扩展功能的一些jar,开发者可以使用
3,App ClassLoader应用程序类加载器。
负责记载classpath中指定的jar包及目录中class,开发者可以直接使用该类加载器,默认的类加载器。
4,Custom ClassLoader启动类加载器
他使用C++实现,是虚拟机自身一部分。所有的其他的类加载器都由Java语言实现,独立于虚拟机之外,并且全部继承自抽象类java.lang.ClassLoader,这些类加载器需要由启动类加载到内存中之后才能去加载其他类。
加载:
加载是类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情。
1,通过一个类的全限定名来获取起定义的二进制字节流。
2,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3,在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
在加载过程中会先检查类是否已加载,检查顺序自底向上,而加载顺序是自顶向下。
连接:
1,验证:为了保证Class文件中的字节流包含信息符合当前虚拟机的要求,不会危害到虚拟机自身的安全。包括文件格式检验,元数据检验,字节码验证,符号引用验证。
2,准备:为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。
这时候进行内存分配的仅包括类变量static,而不包括示例变量,示例变量会在对象实例化时随着对象一块分配在Java堆中。
这里所设置的初始值通常情况下是数据类型默认的零值(0,null,false
等),而不是Java中被显示赋予的值
3,解析:虚拟机将常量池中的符号引用转化为直接引用的过程。
解析动作主要针对类或接口,字段,类方法,接口方法符号引用进行
初始化
类初始化是类加载过程的最后一个阶段,才真正开始执行类中的Java代码,虚拟机规范严格规定了有且只有四种情况必须立即对类进行初始化:
1,遇到new,getstatic,putstatic,invokestatic这四条指令时,如果类还没有进行初始化,则需要先触发起初始化。
2,使用Java.lang.refect包的方法对类进行反射调用时 ,如果类还没有进行过初始化,则需要先触发其初始化。
3,当初始化一个类时发现其父类还没有进行初始化,则需要先触发其父类的初始化。
4,当虚拟机启动时,用户需要执行一个主类,虚拟机会先执行主类。
动态加载与静态加载
Java初始化一个类的时候可以用new 操作符来初始化,也可通过Class.forName的方式来得到一个Class类型的实例,然后通过这个Class类型的实例的newInstance来初始化.我们把前者叫做JAVA的静态加载,把后者叫做动态加载.。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/133799.html