Java语句初始化顺序
- 上一篇文章已经初步探明类加载顺序及原由(当然主要是照搬微笑大神的总结),那么在实际使用中是如何进行语句初始化的呢?
一.在单个类中语句初始化顺序
public class InitClassTest {
public static int staticNum = setStaticNum();
static {
System.out.println("静态代码块");
}
public InitClassTest(){
System.out.println("构造器");
}
{
System.out.println("普通代码块");
}
private int num = setNum();
private static int setStaticNum(){
System.out.println("静态变量赋值");
return 1;
}
private int setNum(){
System.out.println("成员变量赋值");
return 2;
}
public static void main(String[] args) {
System.out.println("--------main方法开始执行---------");
InitClassTest initClassTest = new InitClassTest();
System.out.println("--------main方法结束执行---------");
}
}
结果:
静态变量赋值
静态代码块
--------main方法开始执行---------
普通代码块
成员变量赋值
构造器
--------main方法结束执行---------
将静态块、静态变量、代码块和成员变量位置调换,再将构造函数放最上来看另一种情况:
public class InitClassTest {
public InitClassTest(){
System.out.println("构造器");
}
static {
System.out.println("静态代码块");
}
public static int staticNum = setStaticNum();
private int num = setNum();
{
System.out.println("普通代码块");
}
private static int setStaticNum(){
System.out.println("静态变量赋值");
return 1;
}
private int setNum(){
System.out.println("成员变量赋值");
return 2;
}
public static void main(String[] args) {
System.out.println("--------main方法开始执行---------");
InitClassTest initClassTest = new InitClassTest();
System.out.println("--------main方法结束执行---------");
}
}
结果:
静态代码块
静态变量赋值
--------main方法开始执行---------
成员变量赋值
普通代码块
构造器
--------main方法结束执行---------
根据上面实验,我们大概可以总结一下结论(当然仅仅根据两个例子推理方式不尽完善,中间如果有什么错误欢迎指正):
1.静态块和静态方法总会最先执行,这也和上篇类加载顺序一致,类初始化主要就是为静态变量赋值,因此它们总会在main方法之前执行;
2.不管怎样,构造函数总是最后才会执行的;
3.静态块和静态语句以及成员变量和普通代码块会根据前后顺序依次执行,总的顺序为:(静态变量、静态代码块)-> (成员变量、普通代码块) -> 构造函数
二.在具有继承关系父子类中语句初始化顺序
public class InitClassTest1 {
public InitClassTest1(){
System.out.println("父类构造器");
}
static {
System.out.println("父类静态块");
}
public static int staticNum = setStaticNum();
private int num = setNum();
{
System.out.println("父类普通代码块");
}
private static int setStaticNum(){
System.out.println("父类静态变量赋值");
return 1;
}
private int setNum(){
System.out.println("父类成员变量赋值");
return 2;
}
}
class InitClassTest2 extends InitClassTest1 {
public InitClassTest2(){
System.out.println("子类构造器");
}
static {
System.out.println("子类静态块");
}
public static int staticVal = setStaticVal();
private int val = setVal();
{
System.out.println("子类普通代码块");
}
private static int setStaticVal(){
System.out.println("子类静态变量赋值");
return 1;
}
private int setVal(){
System.out.println("子类成员变量赋值");
return 2;
}
}
class Test {
public static void main(String[] args) {
InitClassTest2 initClassTest = new InitClassTest2();
}
}
结果:
父类静态块
父类静态变量赋值
子类静态块
子类静态变量赋值
父类成员变量赋值
父类普通代码块
父类构造器
子类成员变量赋值
子类普通代码块
子类构造器
还有一种情况,我在子类调用父类的静态变量会怎样:
class Test {
public static void main(String[] args) {
System.out.println(InitClassTest2.staticNum);
}
}
结果:
父类静态块
父类静态变量赋值
1
总结:
1.子类在初始化中如果有父类,会先初始化父类;
2.如果调用子类中的父类静态变量不会初始化子类;
3.父类(静态块、静态变量) -> 子类(静态块、静态变量) -> 父类(成员变量、普通代码块 -> 构造函数) -> 子类(成员变量、普通代码块 -> 构造函数);具体的静态块、静态变量以及成员变量、普通代码块和他们在程序中先后顺序有关;
- 果然实践出真知,这些实例完全印证了上篇说所的类加载顺序,具体原因和时机可以看我上篇文章。
原创不易, 如需转载,请注明出处!
——纯生啤酒_