大佬发的一道笔试题,问以下代码输出什么:
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方法在子类中,所以会先去加载父类,所以父类的各种代码块又会先于子类来执行。静态方法子类重写了,所以直接调用子类的方法。
领会思想就好。。。
感谢大佬。