JVM学习笔记 -- 从一段几乎所有人代码都会犯错的代码开始
废话不多说 看看这段代码。告诉我结果:
import java.io.*; class Test { public static Test t = new Test(); public Test(){ a++; b++; } public static int a; public static int b = 0; public static void main (String[] args) throws java.lang.Exception { System.out.println(t.a + " " + t.b); } }
如果你毫无疑问的答很简单 static 是类所有的,每个实例改变都会变他的值,答案是 1,1 那么。。恭喜你上套了。
你可以亲自试一下结果。 是1,0 这是为什么呢。 原来一个类加载的时候会经历以下步骤:
加载:查找并加载类的二进制数据
连接
-验证:确保被加载的类的正确性 //为什么会检验? 因为.class有可能是手动改的
-准备:为类的静态变量分配内存,并将其初始值转化为默认值
-解析:把类中的符号引用转换为直接引用
初始化:为类的静态变量赋予正确的初始值
回过头再来看最上面的一段程序。发现实例是在static成员上面写的,也就是在赋值之前。
那么在准备阶段, 会为静态变量分配内存,初始值为默认值,这时候 a 和b 都是 0,0 然后创建实例 a++;b++; 此时 a 和b的值都是1;
重点来了。接下来到了初始化过程, 会为静态变量赋予正确的初始值, 由于a没有赋值,所以还为1没有变化,但是b被赋予正确的初始值0。
所以这下真相大白了。 b的真实变化过程是 0-->1-->0。
附上一些笔记:
类的主动使用
1.创建类的实例
2.访问静态变量
3.调用静态方法
4.反射
5.初始化一个类的子类
6.虚拟机启动时候被标明启动类的类
将二进制读入到内存中 放在运行时的方法去内 堆內创建一个Class对象,用来封装类在方法区内的数据结构
加载class的方式
1.从本地系统直接加载
2.网络加载
3.zip jar包加载
4.从专有数据库提取.class
5,将java 源文件动态编译为.class