• 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序


    一、阿里巴巴笔试题:

    public class Test {
    	public static int k = 0;
    	public static Test t1 = new Test("t1");
    	public static Test t2 = new Test("t2");
    	public static int i = print("i");
    	public static int n = 99;
    	private int a = 0;
    	public int j = print("j");
    	
    	{
    		print("构造块");
    	}
    
    	static {
    		print("静态块");
    	}
    
    	public Test(String str) {
    		System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);
    		++i;
    		++n;
    	}
    
    	public static int print(String str) {
    		System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);
    		++n;
    		return ++i;
    	}
    
    	public static void main(String args[]) {
    		Test t = new Test("init");
    	}
    }


    输出:

    1:j    i=0     n=0
    2:构造块    i=1     n=1
    3:t1    i=2     n=2
    4:j    i=3     n=3
    5:构造块    i=4     n=4
    6:t2    i=5     n=5
    7:i    i=6     n=6
    8:静态块    i=7     n=99
    9:j    i=8     n=100
    10:构造块    i=9     n=101
    11:init    i=10     n=102

    二、我们暂且先不看这道题,先回忆一下代码块、构造函数执行顺序的基本知识:

    总体规则:静态代码块 -> 动态代码块 ->构造函数

    静态代码块只在第一次new的时候执行一次,之后不再执行;动态代码块在每次new的时候都执行一次。

    在不涉及继承的情况下:

    1.静态代码块和静态成员变量在加载代码时执行,只执行一次,按照它们出现的顺序先后执行;

    2.动态代码块在每次实例化对象时执行,在构造函数之前执行,多个动态代码块按照它们出现的顺序先后执行;

    在涉及继承的情况下:

    1.执行父类的静态代码块和静态成员变量定义,执行子类的静态代码块和静态成员变量定义;

    2.执行父类的动态代码块,执行父类的构造函数;

    3.执行子类的动态代码块,执行子类的构造函数;

    4.如果父类构造函数中用到的函数被子类重写,那么在构造子类对象时调用子类重写的方法;

    代码:

    public class staticTest {
    	public static void main(String[] args) {
    		A a1 = new B();
    	}
    }
    
    class A{
    	public A(){
    		System.out.println("A constructor.");
    		func();
    	}
    	
    	static{
    		System.out.println("class A static block.");
    	}
    	
    	private int ai = getAi();
    
    	{
    		System.out.println("class A dynamic block.");
    	}
    	
    	private static int asi = getAsi();
    	
    	private int getAi(){
    		System.out.println("class A dynamic int.");
    		return 1;
    	}
    	
    	private static int getAsi(){
    		System.out.println("class A static int.");
    		return 0;
    	}
    	
    	public void func(){
    		System.out.println("A.func()");
    	}
    }
    
    
    class B extends A{
    	public B(){
    		System.out.println("B constructor.");
    		func();
    	}
    	
    	static{
    		System.out.println("class B static block.");
    	}
    	
    	private int bi = getBi();
    	
    	{
    		System.out.println("class B dynamic block.");
    	}
    	
    	private static int bsi = getBsi();
    	
    	private int getBi(){
    		System.out.println("class B dynamic int.");
    		return 1;
    	}
    	
    	private static int getBsi(){
    		System.out.println("class B static int.");
    		return 0;
    	}
    	
    	public void func(){
    		System.out.println("B.func()");
    	}
    }


    输出:

    class A static block.
    class A static int.
    class B static block.
    class B static int.
    class A dynamic int.
    class A dynamic block.
    A constructor.
    B.func()
    class B dynamic int.
    class B dynamic block.
    B constructor.
    B.func()


    三、对阿里巴巴笔试题的分析

    public static int k = 0;
    public static Test t1 = new Test("t1");


    函数先执行到这里,在构造t1的过程中发生了什么呢,通过对程序打断点分析,我发现,程序并没有执行其中的静态代码块,而是执行非静态代码块,为什么呢?我的理解是,“静态代码块只在程序加载的时候运行,并且是按其出现顺序加载的”,而现在我们在构造一个新对象,属于程序加载的时候的一个分支,然后还会走回来继续加载剩下的未加载的静态代码块。所以在这次创建静态对象的过程中,之后执行其中的非静态代码块。

    下面我们看到的两个*****中间的就是在执行该语句的过程中产生的分支:

    **********

    所以接下来执行的是:

    private int a = 0;
    public int j = print("j");

    执行第二句的时候会调用

    public static int print(String str) {
    	System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);
    	++n;
    	return ++i;
    }


    然后执行动态代码块:

    {
    	print("构造块");
    }


    然后调用构造函数:

    public Test(String str) {
    	System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);
    	++i;
    	++n;
    }


    这个顺序就是“动态代码块->构造函数"。

    *************

    然后跳出该分支,继续加载静态代码块:

    public static Test t2 = new Test("t2");


    执行此句会重复上面两个********之间的分支,这里不再赘述。

    然后是:

    public static int i = print("i");
    public static int n = 99;
    
    static {
    	print("静态块");
    }


    最后执行main函数里面的部分,依次调用动态代码块和构造函数,不再赘述。





  • 相关阅读:
    基于jquery自己写滑动门(通用版)
    这一年,做为asp.net程序员我合格吗?
    基于jquery的滚动条滚动固定div(附Demo)
    asp.net获取数据随机显示(原创)
    为昨天一篇博文【asp.net,对于一个有点经验的猴子,我的要求高么?】做点解释
    2012年总结,2013年更精彩。
    放大镜
    be strong
    模拟凡客导航
    Ajax中Get请求与Post请求的区别(转载)
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3357994.html
Copyright © 2020-2023  润新知