类加载内存分析及类的初始化分析
一、Java内存分析:

二、了解:类的加载过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

三、类的加载与ClassLoader的理解
➢加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象.
➢链接: 将Java类的二进制代码合并到JVM的运行状态之中的过程。
➢验证:确保加载的类信息符合JVM规范,没有安全方面的问题
➢准备:正式为类变量(static) 分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
➢解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
➢初始化:
➢执行类构造器<clinit> ()方法的过程。类构造器<clinit> ()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
➢当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
➢虚拟机会保证一个类的< clinit> ()方法在多线程环境中被正确加锁和同步。
public class Test05 {public static void main(String[] args) {A a = new A();System.out.println(A.m);/*1.加载到内存,会产生一个类对应Class对象2.链接,链接结束后 m = 03.初始化<clinit>(){System.out.println(A.m);m = 300;m = 100}m=100*/}
}class A{static {System.out.println("A类静态代码块初始化");m = 300;}static int m = 100;public A(){System.out.println("A类的无参构造初始化");}
}
四、什么时候会发生类初始化?
➢类的主动引用(一 定会发生类的初始化)
➢当虚拟机启动, 先初始化main方法所在的类
➢new一个类的对象
➢调用类的静态成员(除了final常量)和静态方法
➢使用java.lang.reflect包的方法对类进行反射调用
➢当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
➢类的被动引用(不会发生类的初始化)
➢当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
➢通过数组定义类引用,不会触发此类的初始化
➢引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
//测试类什么时候会被初始化
public class Test06 {static {System.out.println("Main被加载");}public static void main(String[] args) throws ClassNotFoundException {//1.主动引用// Son son = new Son();//反射也会产生主动引用//Class.forName("com.reflection.Son");//2.被动引用// System.out.println(Son.b);// Son[] array=new Son[5];System.out.println(Son.M);}
}class Father{static int b = 2;static {System.out.println("父类被加载");}
}class Son extends Father{static {System.out.println("子类被加载");int m = 300;}static int m = 100;static final int M=1;
}
