今天来研究一下含继承、静态成员、非静态成员时Java程序的执行顺序:
一、不含继承,含有静态变量、静态代码块
创建一个子类,该类包含静态变量、静态代码块、静态方法、构造方法
/** * @createtime 2017年3月17日 下午5:17:02 * @description 创建一个子类 */ public class Son{ public static String name = "子类name"; public static long date = new Date().getTime(); public String time = String.valueOf(System.currentTimeMillis()); /** * 静态代码块 */ static{ System.out.println("子类静态代码块"); System.out.println("子类静态代码块日期是:"+String.valueOf(date)); } /** * 非静态代码块 */ { System.out.println("子类非静态代码块"); System.out.println("子类非静态代码块执行时间是:"+time); } /** * 静态方法 * @param names */ public static void getName(String names){ Son.name = names; System.out.println(name); } /** * 默认构造方法 */ public Son(){ this("构造son"); System.out.println("子类默认构造方法"); } public Son(String names){ System.out.println("子类含参构造方法"); this.name = names; } public static void main(String[] args) { getName("son-name"); new Son(); } } /*不继承父类时--执行结果如下: 子类静态代码块 子类静态代码块日期是:1489742299514 son-name 子类非静态代码块 子类非静态代码块执行时间是:1489742299514 子类含参构造方法 子类默认构造方法 */
根据执行结果可以很直观的看出,执行顺序是:
静态代码块->调用的静态方法->非静态代码块->构造方法
这都是有明显输出情况下看到的顺序,还有一些变量的输出也是有顺序的,只是从结果不太容易看出,但是可以通过断点来调试,在调试之前一定要在所有变量、
方法及代码块前打上断点,这样看执行顺序就很明了,我打断点之后发现这个程序的整个执行过程是这样的:
静态变量赋值-->执行静态代码块-->非静态变量赋值-->执行非静态代码块-->调用静态方法-->调用构造方法
二、含继承、且父类也有静态变量、静态代码块和构造函数
1、创建一个子类,该类包含静态变量、静态代码块、构造方法
/** * @createtime 2017年3月17日 下午4:25:26 * @description 定义一个父类 */ public class Father { public static String name = "变量father"; public static long date = new Date().getTime(); public String time = String.valueOf(System.currentTimeMillis()); /** * 静态代码块 */ static{ System.out.println("父类静态代码块"); System.out.println("父类静态代码块日期是:"+String.valueOf(date)); } /** * 非静态代码块 */ { System.out.println("父类非静态代码块"); System.out.println("父类非静态代码块执行时间是:"+time); } /** * 默认构造方法 */ public Father(){ this("构造father"); System.out.println("父类默认构造方法"); } public Father(String name){ System.out.println("父类含参构造方法"); this.name = name; } } /*继承父类时-执行结果如下: 父类静态代码块 父类静态代码块日期是:1489743876335 子类静态代码块 子类静态代码块日期是:1489743876336 son-name 父类非静态代码块 父类非静态代码块执行时间是:1489743876336 父类含参构造方法 父类默认构造方法 子类非静态代码块 子类非静态代码块执行时间是:1489743876336 子类含参构造方法 子类默认构造方法*/
2、让子类Son继承父类Father
/** * @createtime 2017年3月17日 下午5:17:02 * @description 创建一个子类 */ public class Son extends Father{ public static String name = "子类name"; public static long date = new Date().getTime(); public String time = String.valueOf(System.currentTimeMillis()); /** * 静态代码块 */ static{ System.out.println("子类静态代码块"); System.out.println("子类静态代码块日期是:"+String.valueOf(date)); } /** * 非静态代码块 */ { System.out.println("子类非静态代码块"); System.out.println("子类非静态代码块执行时间是:"+time); } /** * 静态方法 * @param names */ public static void getName(String names){ Son.name = names; System.out.println(name); } /** * 默认构造方法 */ public Son(){ this("构造son"); System.out.println("子类默认构造方法"); } public Son(String names){ System.out.println("子类含参构造方法"); this.name = names; } public static void main(String[] args) { getName("son-name"); new Son(); } }
同样打断点调试后发现详细的执行顺序是:
父类静态变量赋值-->执行父类静态代码块 -->子类静态变量赋值 -->执行子类静态代码块--> 调用子类静态方法--> 父类非静态变量赋值-->执行父类非静态代码块
-->执行父类构造方法-->子类非静态变量赋值-->执行子类非静态代码块-->执行子类构造函数
三、结论
根据以上分析,可以得出以下结论:
1、实例化一个子类时,优先实例化父类;
2、静态优先非静态执行;
3、静态变量优先,其次是静态代码块;
4、如果子类和父类都有静态成员,则优先执行父类中的静态成员;