实例化——执行成员变量的赋值语句和构造函数。包括成员变量的赋值,以及{}代码块。自上而下执行。
构造函数最后执行
使用——每个线程一个栈,调用方法,就往里面压一个Stack Frame。方法执行结束后则弹出。实例化对
象后,对象是在堆中,栈中有个引用指向堆中的对象,堆中的对象有个地址指向方法区中的
类的信息
卸载——略
二。直接引用
以下是视为主动使用一个类,其他情况均视为被动使用!
1) 最为常用的new一个类的实例对象(声明不叫主动使用)
2) 直接调用类的静态方法。
3) 对类的静态变量进行读取、赋值操作的
4) 反射调用一个类的方法。
5) 初始化一个类的子类的时候,父类也相当于被程序主动调用了(如果调用子类的静态变量是从父类
继承过来并没有复写的,那么也就相当于只用到了父类的东东,和子类无关,所以这个时候子类
不需要进行类初始化)。
6) 直接运行一个main函数入口的类。
三。类初始化与对象实例化
(1)类初始化流程:
<1>父类静态变量赋值、静态代码块执行(形式如static {})
<2>子类静态变量赋值、静态代码块执行(形式如static {})
对象实例化流程:
<1>父类成员变量赋值、成员代码块执行(形式如{})
<2>父类构造函数
<3>子类成员变量赋值、成员代码块执行(形式如{})
<4>子类构造函数
(2)类初始化只需执行一遍,对象实例化可执行多遍
(3)实例化时需类初始化(没初始化过),但是并不一定是初始化做完再实例化。初始化进行到一半,
遇到实例化,会先执行实例化的部分,再继续执行初始化的部分。初始化可以被实例化即时打断,
但是实例化时建议就不要再实例化自己以及父类相关对象,容易死循环
(4)main方法会在所在类初始化后执行
四。简单例题
梳理至此,应该是把整个加载过程理顺了。我自己网上找了些类似的搞来搞去关于加载执行顺利的题,
都能准确应付了。下面来试试手,也欢迎各位找出各种变态奇葩各种中二的题目或想法来讨论。
Class A extends B{
A(){
System.out.println("A-new");
}
{
System.out.println("A-1");
}
static{
System.out.println("A-static-1");
new A();
}
public static void main(String[] args){
System.out.println("A-main");
}
static{
System.out.println("A-static-2");
}
}
Class B{
B(){
System.out.println("B-new");
}
static{
System.out.println("B-static-1");
}
{
System.out.println("B-1");
}
}
执行结果是:
B-static-1——main函数在A中,A继承自B,故先走父类B的初始化流程,B静态代码块执行
A-static-1——走完父类B的初始化流程后,再走子类A的初始化流程,A静态代码块执行
B-1——其实子类A的初始化流程还没走完,但是遇到了new A(),就直接开始走A的实例化流程,
先走父类B实例化流程,B的成员代码块执行
B-new——继续B的实例化流程,走B的构造函数
A-1——父类B的实例化流程结束,走子类A的实例化流程,A的成员代码块执行
A-new——继续子类A的实例化流程,走A的构造函数
A-static-2——A实例化结束后,继续之前被打断的类A的初始化流程
A-main——main所在类A的初始化结束后,走main方法