Chinaunix首页 | 论坛 | 博客
  • 博客访问: 186128
  • 博文数量: 89
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 828
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-08 10:44
文章分类
文章存档

2014年(9)

2013年(80)

我的朋友

分类: Java

2013-10-08 10:58:05

一、阿里巴巴笔试题:
[java] view plaincopy
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");  
    }  
}  


输出:
[plain] view plaincopy
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.如果父类构造函数中用到的函数被子类重写,那么在构造子类对象时调用子类重写的方法;
代码:
[java] view plaincopy
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()");  
    }  
}  


输出:
[plain] view plaincopy
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()  


三、对阿里巴巴笔试题的分析
[java] view plaincopy
public static int k = 0;  
public static Test t1 = new Test("t1");  


函数先执行到这里,在构造t1的过程中发生了什么呢,通过对程序打断点分析,我发现,程序并没有执行其中的静态代码块,而是执行非静态代码块,为什么呢?我的理解是,“静态代码块只在程序加载的时候运行,并且是按其出现顺序加载的”,而现在我们在构造一个新对象,属于程序加载的时候的一个分支,然后还会走回来继续加载剩下的未加载的静态代码块。所以在这次创建静态对象的过程中,之后执行其中的非静态代码块。
下面我们看到的两个*****中间的就是在执行该语句的过程中产生的分支:
**********
所以接下来执行的是:
[java] view plaincopy
private int a = 0;  
public int j = print("j");  
执行第二句的时候会调用
[java] view plaincopy
public static int print(String str) {  
    System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);  
    ++n;  
    return ++i;  
}  


然后执行动态代码块:
[java] view plaincopy
{  
    print("构造块");  
}  


然后调用构造函数:
[java] view plaincopy
public Test(String str) {  
    System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);  
    ++i;  
    ++n;  
}  


这个顺序就是“动态代码块->构造函数"。
*************
然后跳出该分支,继续加载静态代码块:
[java] view plaincopy
public static Test t2 = new Test("t2");  


执行此句会重复上面两个********之间的分支,这里不再赘述。
然后是:
[java] view plaincopy
public static int i = print("i");  
public static int n = 99;  
  
static {  
    print("静态块");  
}  


最后执行main函数里面的部分,依次调用动态代码块和构造函数,不再赘述。
阅读(557) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~