Java-反射类加载到内存分析
相信大家知道,类加载大概的意思是:当我们要运行编译后的class文件时,会有类加载器 把 class文件加载到内存中;实际上这个比较抽象,说具体点的话,应该是如下:
嗯,好!相信大家看了之后还不懂啊,起初我也是一脸懵逼啊,现在逐个给大家解释。
所谓类加载,细分应该是:类加载,类链接,类初始化。
1. 类加载:由类加载器 class文件加载到内存中(说具体点就是方法去),并在 堆内存创建对应的class对象;
2. 类链接:类链接细分的话也是分为3个步骤:
》验证:校验 类结构是否符合JVM规范
》准备:这个很重要,该阶段是为 类中 的 静态变量,注意是静态变量,为静态变量分配内存空间,并进去默认值的初始化。再提一句,静态变量的赋值和静态代码库的加载是在 类初始化中的,别搞混了
》解析:讲符合引用替换为地址引用(这个不用深究)
3. 类初始化:指的是 为 该类的变量(包括静态和非静态)进行赋值操作 以及 执行一些 预加载代码;下面讲详细点:
》当类初始化的时候,首先会初始化他的父类
》初始化类的时候,会执行类构造器<clinit>方法,这个方法里合并了 该类的类变量和静态代码块,比如代码如下:
public class ClassLoadDemo { static { System.out.println("静态代码块执行了"); str = "20"; } public static String str= "10"; }
那 <clinit>方法大概就是这样:
<clinit>(){ System.out.println("静态代码块执行了"); str = "20"; str = "10"; }
需要大家注意一点:静态变量和静态代码块谁先加载,取决于他们在代码中的顺序,比如上面的静态代码块 放在 静态变量的前面,那静态代码块就先加载。
还是给一段代码,然后详细说下大概的类加载过程是怎样的吧,如下:
1. 该java文件,经过编译后会生成两个class文件,分别是Test05.class和 A.class
2. 当使用 java.exe 执行Test05.class时,Test05.class会先加载到方法区中,接着A.class也同样加载到方法区,此时他们的数据结构会发送改变,变成运行时数据结构
3. 在堆内存中生成 对应的两个class对象
4. 在方法区中,为 静态变量m 分配内存,并赋予默认值 0
5. 接着初始化Test05类,执行 <clinit>方法,即 执行 static代码块 和 m=100,则此时m=0
6. main方法进栈,执行 A a = new A()时,会先初始化A类,执行其<clinit>,接着在堆内存创建 A 对象,执行构造A的构造方法
7. 然后打印A.m,打印结构是m=100
大概的过程就是这样上面的步骤,然后需要细道的是:在堆内存中的 实例对象 中的 数据 是从class对象获取的,而class对象的数据又是从 方法区的字节码文件的运行时结构获取的。
好了,就说这么多啦!!