java文件想要被jvm识别首先要被转化成class文件,class文件是一个16进制的文件
当java文件转化成class文件后就会出现一个问题,是jvm主动获取这个class文件还是class文件自己进入jvm。
jvm就出现了类加载机制。
类加载机制就是jvm主动去获取文件夹中的类。
主动获取的条件:
1.外部调用这个类,读取内部的final和static变量
2.new一个对象
3.调用静态方法
类加载机制的步骤
Loading , linking, initialzing
(1) 装载 loading :各个类装载器扫描自己负责的文件夹下(创建class常量池和运行时常量池)
类装载器
启动类加载器(Bootstrap classLoader):又称为引导类加载器,由C++编写,无法通过程序得到。主要负责加载JAVA中的一些核心类库,主要是位于<JAVA_HOME>/lib/rt.jar中。
拓展类加载器(Extension classLoader):主要加载JAVA中的一些拓展类,位于<JAVA_HOME>/lib/ext中,是启动类加载器的子类。
应用类加载器(System classLoader): 又称为系统类加载器,主要用于加载CLASSPATH路径下我们自己写的类,是拓展类加载器的子类。
但是又会出现一个问题,当各自文件夹下面都有一个 java.lang.String 文件时。这个类加载器会如何加载。
双亲委派
三个类加载器实际上属于继承关系,
classLoader(){
//先交给自己的父类来扫描,如果扫描到了这个类,装载然后结束
//父类没有扫描到则交给子类来扫描,扫描到了装载然后结束
//如果没有扫描到,抛出 异常
}
想要破环这个双亲委派,简单的就是重写这个classLoader方法。
(2)链接 linking:准备:分配方法区空间,主要是类变量(static修饰的)并设置初始值。(创建了全局字符串池)
检查:确保被加载类的正确性
解析:将符号引用转化为直接引用
(3)初始化 init : 类变量的赋值和static代码块的执行。
子类的初始化是从父类开始的,父类的静态代码块和类变量赋值--->子类的静态代码块和类变量赋值
类会在外部主动调用的时候进行初始化步骤:
1. 类的实例化(new,反射等)
2. 调用类的静态方法
3. 调用类或者某个接口的静态变量
4. 子类进行了初始化
5. 调用反射,Class.forName()和java.reject包里面的方法
6. 虚拟机启动某个标注为启动类的类(mian方法)
问题:
1.因为实例化一个子类的时候会先执行父类的构造方法,所以是不是也相当于实例化了一个父类对象?
实例化对象的时候确实会执行一次构造方法,但是执行构造方法只是为了为变量赋值,并不能说实例化了对象。
2.加载后的类会放在哪里?
没有实例化的class会被ClassLoader在堆里面创建一个代表这个类的class对象作为访问方法区的入口。