一道无聊的笔试题以及从中的收获

大佬发的一道笔试题,问以下代码输出什么:

public class Test {
	
	static Test t = new Test();
	
	static {
		System.out.println("1");
	}
	
	{
		System.out.println("2");
	}
	
	public Test() {
		System.out.println("3");
		System.out.println("a="+a+",b="+b);
	}
	
	public static void func() {
		System.out.println("4");	
	}
	
	int a = 110;
	static int b = 112;
	
	
	
	public static void main(String[] args) {
		func();
	}
}

看这道题,我的第一反应就是这题太无聊了,谁工作中这么写。
然后随便答了一下,答错了。

执行main方法时,首先会先加载类相关信息,在这个阶段中,就会先依次按照顺序执行静态变量的加载及静态代码块的部分。所以在这段代码中,执行的顺序是这样的:

1、按顺序执行第一条static语句:static Test t = new Test();
2、此时会new一个Test对象,所以在执行构造方法之前,先初始化代码块和非静态变量。于是{
System.out.println(“2”);
} 这个非静态代码块被执行,输出2,然后变量a被初始化为110,接下来执行Test构造方法,输出3,因为此时static语句还没执行到变量b的部分,所以b没有被赋值,仍然为0,所以输出“a=110,b=0”
3、接下来继续按顺序执行static部分,该执行静态代码块了,于是输出1,再然后变量b被初始化为112。
4、最后进入main方法中执行静态方法,输出4

运行代码,输出结果如下:

2
3
a=110,b=0
1
4

如果将第一句代码static Test t = new Test();放在不同的位置,甚至可以在main方法里再new一个Test对象,那么又会有不同的输出顺序,但是原则上应该都是先按代码顺序把static部分都执行完毕,然后再执行main方法中的逻辑。我试了几个不同的位置,图就不贴了。

值得一提的是,静态代码块是随着类的加载而执行,而且只执行一次。所以不管new多少个对象,静态代码块都是只执行一次。

那么问题又来了,静态代码块在父类和子类的执行顺序又是怎么样的?于是我抄了一段代码跑了一下:

public class TestSon extends TestFather {
	
	static {
		System.out.println("子类静态代码块");
	}
	
	{
		System.out.println("子类非静态代码块");
	}
	
	public TestSon() {
		System.out.println("子类构造方法");
	}
	
	public static void func() {
		System.out.println("子类的静态方法");
	}

	public static void main(String[] args) {
		func();
		TestSon t = new TestSon();
	}

}


class TestFather {
	
	static {
		System.out.println("父类静态代码块");
	}
	
	{
		System.out.println("父类非静态代码块");
	}
	
	public TestFather() {
		System.out.println("父类构造方法");
	}
	
	public static void func() {
		System.out.println("父类的静态方法");
	}
	
}

运行结果如下:

父类静态代码块
子类静态代码块
子类的静态方法
父类非静态代码块
父类构造方法
子类非静态代码块
子类构造方法

依然是静态部分优先的原则,而main方法在子类中,所以会先去加载父类,所以父类的各种代码块又会先于子类来执行。静态方法子类重写了,所以直接调用子类的方法。

领会思想就好。。。

感谢大佬。

你可能感兴趣的:(java)