虚拟机的声明周期可以分为三个阶段:
虚拟机的启动
虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现来指定的。
虚拟机的执行
一个运行中的Java虚拟机有这一个清晰的任务就是执行Java程序,程序开始执行时虚拟机,当程序运行结束时,虚拟机就结束,在执行一个Java程序的时候,真真正正执行的是一个叫做Java虚拟机的进程。
虚拟机的退出
虚拟机的退出又分为几种情况:
程序正常执行结束程序运行过程中遇到异常而终止操作系统出现错误而导致Java虚拟机进程终止某个线程调用Runtime类或System类的exit方法,或者Runtime类的halt方法,并且Java安全管理器也允许这次exit或者halt操作。还有一种就是JNI(Java Native Interface)规范描述了用JNI Invocation API来加载或卸载Java虚拟机时,Java虚拟机退出的情况。 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称为虚拟机的类加载机制,在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的。
类加载器的作用就是将类class文件加载到内存中,对方法区中的类信息的访问都需要经过这个Class对象
类的加载过程分为五个阶段
类加载后会在堆区生成一个唯一的Class对象。
在准备阶段如果变量是final static修饰的常量则不会赋予零值,而是会直接赋值如:以下代码会被直接赋值为123;
public static int value = 123类构造器是收集静态代码和静态变量形成的,如果没有静态变量和静态代码块则并不会有类构造器,初始化过程就是执行类构造器的过程。
注意:执行接口的类加载器并不需要先执行父接口的类构造器,因为只有当父接口中定义的变量被使用时,父接口才会被初始化,此外,接口的实现类在初始化时也一样不会执行接口的类构造器
对类的主动使用会触发类的初始化
java程序对类的主动引用:
添加一点:深入理解Java虚拟机第三版中提到当一个接口中定义了jdk8新加入的默认方法(被default关键字修饰的接口方法)时,如果这个接口的实现类发生了初始化,那改接口要在其之前被初始化
对类的别动引用不会触发类的初始化
java程序对类的被动引用:
通过子类引用父类的静态字段不会导致子类的初始化通过数组定义来引用类,不会触发此类的初始化常量在编译器会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化在jdk9中,扩展类加载器被平台类加载器所取代
应用程序类加载器用户自定义的加载器:
为什么要自定义类加载器:
如何自定义类加载器:
自定义的类加载器需要继承ClassLoader,有关ClassLoader
如何获取类加载器:
通过方式一获取类加载器,如果获取到的结果为null,则表示是一个引导类加载器
例如:
// shareData是自定义类 ,String类是由引导类加载器加载的 public static void getClassLoader(){ String s = new String(); System.out.println("类加载器"+s.getClass().getClassLoader()); ShareData shareData = new ShareData(); System.out.println("类加载器"+shareData.getClass().getClassLoader()); }注意:判断两个class对象是否是同一个类要注意两点:
类的全限定类型是否相等加载类的类加载器是否相同沙箱安全机制
双亲委派机制可以保护核心类不被篡改:
自定义一个java.lang.String类,在main方法中会报错
package java.lang; /** * @author mypc * @create 2020 上午 11:40 */ public class String { // static{ System.out.println("我是自定义的String类的静态代码块"); } public static void main(String[] args) { System.out.println("hello,String"); } }即使这个类是自定义的,理应由应用程序类加载器加载,但是由于双亲委派机制的存在,它会首先将该类交给它的父类加载器扩展类加载器加载,扩展类加载器又会交给它的父类加载器引导类加载器加载,而java.lang.String这个类在jdk的核心类库中存在,所以它会直接加载核心类库中的java.lang.String,不会加载我们自定义的java.lang.String,这样就防止了核心API被随意串改。java的核心类java.lang.String没有main方法,所以报错. 以上内容是根据尚硅谷的视屏和深入理解Java虚拟机第三版整理的笔记,如有错误请指出
