先看一道Java面试题:
 1 public class Baset {
 2     private String baseName = "base";
 3     // 构造方法
 4     public Baset() {
 5         callName();
 6     }
 7     // 成员方法
 8     public void callName() {
 9         // TODO Auto-generated method stub
10         System.out.println("basename:" + baseName);
11     }
12   //静态内部类
13     static class Sub extends Baset {//static必须写在开头
14         // 静态字段
15         private String baseName = "sub";
16         public Sub() {
17             callName();
18         }
19         // 重写父类的方法
20         public void callName() {
21             System.out.println("subname:" + baseName);
22         }
23     }
24 
25     public static void main(String[] args) {
26         Baset base = new Sub();
27     }
28 }
求这段程序的输出。
解答此题关键在于理解和掌握类的加载过程以及子类继承父类后,重写方法的调用问题:
一、从程序的执行顺序去解答:
1.编译;当这个类被编译通知后,会在相应的目录下生成两个.class 文件。一个是 Base.class,另外一个就是Base$Sub.class。这个时候类加载器将这两个.class 文件加载到内存
2、Base base= new Sub():
声明父类变量base对子类的引用,JAVA类加载器将Base,Sub类加载到JVM(Java虚拟机);
3、JVM为Base,Sub 的的成员开辟内存空间
此时,Base 和Sub类中的值为null;
4、new Sub();
这个时候会调用Sub类的隐式构造方法,
Sub的构造方法本质为:
public Sub(){
super();// 调用父类的构造方法。必须在构造方法中的第一行,为什么呢?这是因为在一些程序的升级中,要兼容旧版本的一些功能,父类即原先的一些初始化信息也要保证 //被执行到,然后执行当前
baseName = "sub";//子类字段初始化
}
new Sub()执行到super()这行代码也就是跑到父类中去执行了,我们跳转到父类中的无参构造方法中执行,最后执行Sub()中的baseName = "sub"
5、public Base() ;
父类无参构造方法的本质为:
public Base(){
baseName= "base";//父类字段初始化
callName();
}
即将父类的baseName赋值为“base”,赋值后调用callName();
6、callName()方法在子类中被重写,因此调用子类的callName(),子类的callName方法执行,打印输出的是子类的baseName 字段的值,而这个时候子类的构造函数中字段的赋值还未执行。
7、父类的构造函数执行完毕,这个时候又回到子类当中,从super()的下一行继续执行,这个时候才为子类字段baseName 分配好存储空间,随后为其赋值:
可见,在baseName = "sub"执行前,子类的callName()已经执行,所以子类的baseName为默认值状态null;
二、另写两个程序,进行更具体的分析
1、第一个程序:
 1 public class InitialOrderTest {
 2 //    变量
 3     public String field = "变量";
 4 //  静态变量
 5     public  static  String staticField="静态变量";
 6 //父类静态方法    
 7     public static void Order(){
 8         System.out.print("父类静态方法");
 9         System.out.println("staticField:"+staticField);
10     }
11 
12 //  静态初始代码块
13     static{
14         System.out.println("静态初始化块");
15            System.out.println("staticField:"+staticField);
16        }
17 //   初始化代码块  
18       {
19           System.out.println("初始化代码块");
20           System.out.println("field:"+field);
21        }
22 //   构造函数
23    public InitialOrderTest(){
24        System.out.println("构造器");
25        
26    }
27  
28    public static void main(String[] args) {
29        System.out.println("-----[[-------");
30        System.out.println(InitialOrderTest.staticField);
31        InitialOrderTest.Order();
32        System.out.println("------]]------");
33        InitialOrderTest i = new InitialOrderTest();
34        System.out.println("-----[[-------");
35        System.out.println(InitialOrderTest.staticField);
36        InitialOrderTest.Order();
37        System.out.println("------]]------");
38       
39    }
40 }
执行结果为:
第一个程序总结:
1)、java中的块分为静态块(static{})和非静态块({}),这两种的执行是有区别的:
非静态块的执行时间是:在执行构造函数之前。 静态块的执行时间是:class文件加载时执行。
static类型的属性也是在类加载时执行的。
2)、可见Java类的实例变量初始化的过程:
static类型的成员属性执行,静态块(static{})按顺序执行,然后非静态成员变量初始化,非静态代码块({})执行,最后执行构造方法。
static类型与static块按先后顺序执行。
---------------------------------------------------------------------------------------------------------------------------------------------------
2、第二个程序:
 1 public class BaseTest {
 2     // 父类变量
 3     private String baseName = "base";
 4     // 父类静态变量
 5     private static String staticField = "父类静态变量";
 6     // 父类静态方法
 7     public static void Order() {
 8         System.out.println("父类静态方法-");
 9         System.out.println("staticField:" + staticField);
10     }
11     // 父类静态初始代码块
12     static {
13         System.out.println("父类静态初始化代码块-");
14         System.out.println("staticField:" + staticField);
15     }
16     // 初始化代码块
17     {
18         System.out.println("父类非静态初始化代码块-");
19         System.out.println("baseName:" + baseName);
20     }
21     // 构造函数
22     public BaseTest() {
23         System.out.println("父类构造方法");
24         callName();
25     }
26     // 成员方法
27     public void callName() {
28         System.out.println("父类callName方法-");
29         System.out.println("baseName:" + baseName);
30     }
31 
32     // 静态内部类
33     static class Sub extends BaseTest {
34         // 子类变量
35         private String baseName = "sub";
36         // 子类 静态变量
37         private static String staticField = "子类静态变量";
38 
39         // 子类静态方法
40         public static void Order() {
41             System.out.println("子类静态方法-");
42             System.out.println("staticField:" + staticField);
43         }
44 
45         // 子类静态初始化代码块
46         static {
47             System.out.println("子类静态初始化代码块-");
48             System.out.println("staticField:" + staticField);
49         }
50         // 子类非静态初始化代码块
51         {
52             System.out.println("子类非静态初始化代码块-");
53             System.out.println("baseName:" + baseName);
54         }
55 
56         public Sub() {
57             System.out.println("子类构造方法");
58             callName();
59         }
60 
61         public void callName() {
62             System.out.println("子类重写父类callName方法-");
63             System.out.println("baseName:" + baseName);
64         }
65     }
66 
67     public static void main(String[] args) {
68         
69         BaseTest b = new Sub();
70 
71         System.out.println("-----[[-------");
72         Sub.Order();
73         System.out.println(Sub.staticField);
74         System.out.println(BaseTest.staticField);
75         BaseTest.Order();
76         System.out.println("------]]------");
77 
78     }
79 }
执行结果:
   
第二个程序总结:
     1)、可见Java初始化的顺序:    
 1  1 父类静态变量初始化
 2  2 父类静态代码块-static{ }
 3  3 子类静态变量初始化
 4  4 子类静态代码块-static{ }
 5  5 父类非静态变量初始化
 6  6 父类非静态代码块-{}
 7  7 父类构造方法
 8  8 子类非静态变量初始化
 9  9 子类非静态代码块-{}
10 10 子类构造方法
Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序
原文:http://www.cnblogs.com/lubocsu/p/5096731.html