java的内存分析
- 先上一张图看看大纲:
类的加载过程
- 当程序要使用某个类时,如果该类没有被加载在内存中,则该类要经过以下三个步骤进行初始化:
- 类的加载: 将类的对应的class文件读入内存中,并为其创建一个java.lang.Class对象,该过程由类加载器完成。值得注意的是一个类或者一个对象只会创建一个对应的java.lang.Class对象
- 类的链接:将java类的二进制代码合并到JVM的运行环境中去,首先对代码的准确性进行验证,再者准备阶段,为static分配内存和设置默认值。这也是static修饰符修饰的变量或方法可以直接使用的原因,最后是对引用类型的转换,将自己定义的类,转换为真实的引用类型。
- 初始化:JVM虚拟机通过执行构造器()方法的过程,将所有的类变量赋值的过程和static修饰的静态代码块的语句合并生成,并且在初始化一个类时会去考虑类的父类是否初始化,若父类没有初始化则对父类进行初始化。
使用一个实际的例子来模拟类的加载过程
package com.reflection;
//处理类的加载和内存分析
public class Demo03 {
public static void main(String[] args) {
//创建对象
A a = new A();
//直接调用静态方法
System.out.println(A.m);
}
}
//创建一个类,创建对应的方法来便于分析内存的变化
class A{
//创建静态代码块
static {
System.out.println("A类静态代码块的初始化");
m=300;//因为静态变量是在类创建时与类一同创建的所有,在这m可以直接使用
}
//创建一个静态变量
static int m=100;
//创建无参构造
public A() {
System.out.println("A类的无参构造初始化");
}
}
- 画图分析:
- 为什么m=100:
- 原因解释:
/*1.内存加载,一个类产生一个对应的Class对象
2.链接:m初始值=0
3.初始化:
调用<clinit>(){
//将所有类的变量的赋值和static的初始化合并
System.out.println("A类静态代码块的初始化");
m=300;
//因为静态变量是在类创建时与类一同创建的所有,在这m可以直接使用
static int m=100;
}
==由上可知:==在A类静态代码块的初始化输出后对m进行了第一次赋值,m=300,随后又对m第二次赋值,m=100。