JVM类加载笔记

类加载过程

 

1-JVM加载类粗略分可以分为三步

a-加载

将class字节码文件加载到内存,字节码的来源可以有很多,本地文件、zip包、数据库等都可以作为字节码来源。

类加载器得到字节码后,将其转换成运行时数据结构存入方法区。同时,在堆中生成一个java.lang.class对象作为方法区中数据的访问入口。

b-链接

链接又可以分为验证、准备、解析。是将二进制代码合并到JVM运行状态中的过程。

验证:确保加载的数据符合jvm规范且没有安全问题。

准备:正式为static变量分配内存并初始化。static的类变量的内存都在方法区中分配。

解析:将虚拟机常量池内的符号引用改为直接引用

c-初始化

初始化是执行类构造器()方法的过程。初始化一个类时如果发现其父类没有初始化那么会先初始化父类。

初始化之后类就可以使用了,使用完毕需要卸载。

 

2-类的主动引用(一定会发生类的初始化)

- new 一个类的对象

- 调用类的静态成员或静态方法(非final修饰)

- 反射调用

- 在类没有初始化时,初始化该类的子类

-执行 java xxx启动虚拟机时,xxx会被初始化

 

 

3-类的被动引用(不会发生类的初始化)

- 引用类的静态常量(static final修饰)不会触发类初始化

- 定义该类的数组类型(A[] as = new A[]{})

- 访问由父类声明的静态域不会初始化该类。

A的父类有static修饰的变量name

A没有声明name但是从父类继承了,所以有属性A.name.

当访问A.name时,A不会初始化,jvm会去检查真正声明name的类是否初始化过,没有则初始化声明这个变量的类。

public class Demo {
    public static void main(String[] args) {
        System.out.println(A.name);
    }
}

class A extends AFather{
    static {
        System.out.println("A - static");
    }
    public static final int MAX=100;
}

class AFather{
    static String name;
}

以上代码输出结果为null,没有输出类A的初始化语句A - static。

 

类加载器

类加载器的层级关系

bootstrap classLoader -> sun.misc.Launcher$ExtClassLoader -> sun.misc.Launcher$AppClassLoader -> 自定义classLoader

类加载器采用双亲委派机制的好处

双亲委派机制是指,当一个classLoader类接收到加载任务时,优先将任务委托给父类执行,父类也同样如此。若父类不能执行则自再尝试加载。如果自己也加载不了则报错。

因为classLoader的初代类为bootstrap classloader,它负责加载java的核心类。如果它的子类收到的加载任务是加载一个同java核心类名字相同的类时,按照双亲委派模式的工作方式,该加载任务优先由bootstrap classLoader来执行,加载器执行加载时需要先检查是否已经加载过了该类,因为新加载的类同java核心类同名,所以显示该类已经加载过了,无需加载。避免了安全问题,保证了用户不能自己定义java.lang.Object类。

同一个类被一个加载器加载两次,JVM认为是同一个类。 同一个类被不通的加载器加载,JVM认为这不是同一个类。

你可能感兴趣的:(JAVA开发)