记录下复习JVM想的几个东西
搞了半天,原来初始化阶段cinit和init都有,一直在想cinit是初始化阶段那init在什么时候呢,中途又一度陷入final,final static…
/**
* <clinit>&&<init>
*/
public class TestMain {
// public static TestMain t = new TestMain();
static{
System.out.println("代码块被执行");
// System.out.println(i);
System.out.println("1."+TestMain.i);//为什么这里不算前向引用呢?因为在类的准备已经将i赋初值了
new TestMain();
System.out.println("2."+TestMain.i);
}
public static int i = 1;
public TestMain(){
System.out.println("如果该输出结果为0,则意味着i变量还没有被初始化,而是int类型的默认值0");
System.out.println("构造函数被执行,此时i="+ i);
i = 2;
}
public static void main(String[] args) {
//因为main在TestMain内部,所以TestMain在main方法执行时被clinit,而不是在第二行"TestMain.i"的时候clinit
//证明:如果不是,则结果会先输出下边第一句,然后才会初始化TestMain,进而输出初始化的时候的输出语句。程序结果并没有先输出第一句,而是在初始化完成后输出,所以证明成立。
// System.out.println("如果该结果输出为1,则意味着静态变量i的初始化在代码块之后执行了");
// new TestMain();//这样的化就执行了<init>将对象实例化了
// <init>会执行哪些?
// 1. 父类变量初始化
// 2. 父类语句块
// 3. 父类构造函数
// 4. 子类变量初始化
// 5. 子类语句块
// 6. 子类构造函数
System.out.println("3."+TestMain.i);//这个阶段没有将对象实例化,只是访问了类的静态变量在前执行了<cinit>,当然作为主函数也会执行<cinit>
// <init>实在实例化的时候进行的
// 实例化一个类有四种途径:
// 调用new操作符;
// 调用Class或java.lang.reflect.Constructor对象的newInstance()方法;
// 调用任何现有对象的clone()方法;
// 通过java.io.ObjectInputStream类的getObject()方法反序列化
}
}
#1 代码块被执行
#2 1.0
#3 如果该输出结果为0,则意味着i变量还没有被初始化,而是int类型的默认值0
#4 构造函数被执行,此时i=0
#5 2.2
#6 3.1
|
↓
1.首先准备阶段赋初值,该0给0,该/u0000给/u0000
2.然后进行clinit,提取static一起执行,然后就出现了 #2 #3
3.new!执行<init> 调用public TestMain() 称之为实例的初始化,出现 #3 #4,当然,要是有非static代码块也会执行
4.回到上一层的clinit中执行 #5
6.mian()中 #6
cinit
Java在编译之后会在字节码文件中生成方法,称之为类构造器
执行哪些?
-
- 父类静态变量初始化
-
- 父类静态语句块
-
- 子类静态变量初始化
-
- 子类静态语句块
init
Java在编译之后会在字节码文件中生成方法,称之为实例构造器,也被成为类
的
构造器
-
- 父类变量初始化
-
- 父类语句块
-
- 父类构造函数
-
- 子类变量初始化
-
- 子类语句块
-
- 子类构造函数
也就是构造函数和语句块
cinit肯定在init前面执行,cinit中可能执行init,假如静态代码块中有new变量,或者有静态变量直接用new赋值,就会在cinit中调用init完成类的构造