1.java类加载过程

类加载是用来加载class的,它负责将class的字节码形成转换成内存形式的class对象.

1.类的生命周期

java使用类加载器加载某个类_类加载过程

2.什么时候进行类加载

  1. 使用new实例化对象的时候:读取或配置一个类的静态字段(被final修饰,已在编译期把结果放入常量池的静态字段除外)的时候;调用一个类的静态方法的时候
  2. 使用java.lang.reflect包的方法对类进行反射调用的时候.如果类没有进行过初始化,则需要先触发其初始化
  3. 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
  4. 当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类

3.加载

加载这个阶段主要完成三件事情:
(1) 通过一个类的全限定类名获取到类的class文件
(2)将class文件中的字节流按照虚拟机规定的运行时的数据结构存储在方法区中
(3) 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
获取class文件的途径很多,可以从网络获取,压缩包获取,运行时计算获取(动态代理)等等

4.验证

验证的目的:确保class文件的字节流中包含的信息符合当前虚拟机的要求,不会危害虚拟机自身的安全
步骤:
文件格式验证,元数据验证,字节码验证,符合引用验证.其中文件格式验证是直接对字节流进行操作的,其余3项都是在方法区进行的.

5.准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所需要的内存,都将在方法区中进行分配。这里有概念容易混淆:第一这时候进行内存分配仅包括类变量(被static修饰的)不包括实例变量,实例变量将随着对象实例化时一起在Java堆中分配内存。第二这里所说的初始值,通常情况下是数据类型的0值或者null值(特殊的两个是常量类—被final修饰的是直接的值,枚举)

6.解析

解析阶段主要是完成符号引用替换为直接引用,部分初始化也可以在这个阶段完成,比如类或者接口中被final修饰的类成员变量的初始化阶段就是在这个阶段完成的。这么说可能会引起误解,类成员变量的初始化本来就是在这个阶段完成的,比如public static Integer A=10,那么在解析阶段,A的初始化值为NULL,至于A=10的初始化动作,一般是在初始化阶段完成的。而如果是public static final Integer A=10,那么这时A的初始化A=10是在解析阶段就直接完成了的

7.初始化

初始化阶段主要是给类的成员变量进行初始化值,在这个阶段,虚拟机会自动创建一个方法,我们称之为类构造器,这个方法的要执行的内容主要包括两部分,类成员变量的初始化和静态代码块。它们的执行顺序按照在类中的定义的顺序。其中,静态代码块中可以对其前面定义的类成员变量赋值和访问,但不可以对其后定义的类成员变量访问,但可以赋值。
  触发类初始化动作的方式:
  1)new 对象实例或者显式的调用类的静态方法或访问或设置类的静态成员变量。
  2)通过java.lang.reflect中的方法对类进行反射调用。
  3)当初始化一个类的时候,如果发现其父类尚未被初始化,则先初始化其父类。
  4)当虚拟机启动时,用户需要指定一个要执行主类(main方法所在的类),虚拟机会先初始化这个主类。
  5)在使用jdk1.7的动态语言支持时,被解析成的方法句并未被初始化,则要先初始化。

2.类加载器

1.类加载器

通过一个类的全限定名来获取描述此类的二进制字节流这个动作放到java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类,实现这个动作的代码模块成为"类加载器"

2.有哪几种类加载器,他们的职责是什么,之前存在怎么样的约定

1.启动类加载器(BootStrapClassLoader),主要是负责加载jre/lib/rt.jar相关的字节码文件的

2.扩展类加载器(ExtensionClassLoader),主要负责加载jre/lib/ext/*.jar这些jar包的,该类在jdk1.9中改名为Platform class loader,其父类加载器为null

3.应用程序类加载器(ApplicationClassLoader),主要负责加载用户自定义的类以及classpath环境变量所配置的jar包,该类\加载器在jdk1.9的时候改名为system ClassLoader ,其父类加载器为ExtensionClassLoader

4.自定义类加载器(UserClassLoader),主要负责加载程序员指定的特殊目录下的字节码文件的.大多数情况下,自定义加载器只需要继承ClassLoader这个抽象类,重写findClass()和loadClass()两个方法即可

java使用类加载器加载某个类_java使用类加载器加载某个类_02

3.类加载机制

类加载机制主要有三种:
1.全盘加载 — 在加载某一个.class文件时,默认也会连同该类所依赖的.class一起加载
2.缓存机制 — 在所有类加载器已经加载过的.class文件都会保存到缓存中,下次使用该.class文件时,JVM会优先从缓存中查找,若没有,才会去加载指定的字节码文件,这也是为什么当字节码文件变换后,需要重启JVM后才能看到修改效果的原因
3.双亲委派 — AppClassLoader 只负责加载 Classpath 下面的类库,如果遇到没有加载的系统类库怎么办,AppClassLoader 必须将系统类库的加载工作交给 BootstrapClassLoader 和 ExtensionClassLoader 来做
举例:儿子(App)要星星, 他自己实现不了, 就找他老爹(Ext)要, 他老爹能实现的话就给他了, 实现不了, 就找他爷爷(BootStrap)要, 说: 你孙子要天上的星星. 他爷爷如果能实现就给了, 如果也实现不了, 就会告诉他爹(Ext), 让你儿子(App)自己实现吧.

相关扩展知识点:

  • Java虚拟机的基本机构?
  • 什么是类加载器?
  • 简单谈一下类加载的双亲委托机制?
  • 普通Java类的类加载过程和Tomcat的类加载过程是否一样?区别在哪?
  • 简单谈一下Java堆的垃圾回收机制?