本文参考jdk1.8,由于内存分析对理解反射也有很重要的辅助作用,所以笔者也将一些基础知识列出,有不对的还望指正
public class JvmTest { public static void main(String[] args) { NewTest test=new NewTest(); System.out.println(test.m); } /** * 1.首先,在第一阶段类加载,即在堆中创建Class * 2.然后到类链接阶段:设置默认值,分配内存,此时m=0 * 3.然后再对类进行初始化 * 先收集静态代码块,此时m=100,然后类变量的赋值动作,就是m=300 * 所以合并后的代码就是:m=100;m=300,所以最终m的值是300 */ } class NewTest{ static{ System.out.println("初始化静态代码块"); m=100; } static int m=300; public NewTest(){ System.out.println("初始化无参构造器"); } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NC22h1Cq-1627019158275)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210723113455832.png)]
类的主动引用(一定会发生类的初始化)
类的被动引用(不会发生类的初始化)
public class Test01 { static { System.out.println("main类被加载"); } public static void main(String[] args) throws ClassNotFoundException { /** * 主动引用 */ son s=new son();//依次输出main类被加载 父类被加载 子类被加载 //反射方法 Class.forName("son");//依次输出main类被加载 父类被加载 子类被加载 /** * 被动调用 */ //通过子类引用父类的静态变量,不会导致子类初始化 son.f=2;//依次输出 main类被加载 父类被加载 //数组定义类引用 son[] sons=new son[10];//只输出 main类被加载 //引用常量不会触发此类的初始化 System.out.println(son.s2);//只输出 main类被加载 9 } } class father{ static int f=1; static { System.out.println("父类被加载"); } } class son extends father{ static int s=2; static{ System.out.println("子类被加载"); } static final int s2=9; }
将class字节码内容记载到内存中,并将这些静态数据转换成方法区的运行是数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
一旦一个类被加载到类加载器中,它将维持加载一段时间,不过JVM垃圾回收机制可以回收这些Class对象