讲到类的初始化和实例化(见我的《Class的生命周期》),不得不提提初始化和实例化的顺序,我想这也是一直困扰了很大一部分人。
从大流程来说,类肯定是先初始化,再实例化的,这里得出第一个顺序:
静态域 --> 实例域 --> 构造函数。另外要符合任何子类的动作都会触发父类:父类 --> 子类。所以得出原则:【先静态后实例;先父类后子类】
而且同一个域的顺序可以分成两步: 创建-->赋值
对于静态域,其先经过链接创建静态变量,赋default值;再到初始化阶段给静态变量赋assign值和执行静态代码块。同理于实例域,也是分成创建和赋值两个部分,不同的只是加入构造函数(形参和代码块):先创建实例变量和构造函数形参以default值,然后对变量和形参赋assign值和执行实例代码块,最后执行构造函数的代码。
前提先要执行父类,再到子类;另外同一层次的就按从上到下顺序执行,如下面例子。
package com.jscai.java.classLoader; public class LoaderLazy { { System.out.println("Parent Instance Code"); } private PrintTmp p1 = new PrintTmp("Parent Instance Member"); static { System.out.println("Parent Static Code"); } private static PrintTmp p2 = new PrintTmp("Parent Static Member"); public LoaderLazy() { System.out.println("Parent Constuctor"); } } class SubLoaderLazy extends LoaderLazy { { System.out.println("Sub Instance Code"); } private PrintTmp p1 = new PrintTmp("Sub Instance Member"); static { System.out.println("Sub Static Code"); } private static PrintTmp p2 = new PrintTmp("Sub Static Member"); public SubLoaderLazy() { System.out.println("Sub Constuctor"); } } class PrintTmp { public PrintTmp(String strOut) { System.out.println(strOut); } } SubLoaderLazy test = new SubLoaderLazy();
console:
Parent Static Code
Parent Static Member
Sub Static Code
Sub Static Member
Parent Instance Code
Parent Instance Member
Parent Constuctor
Sub Instance Code
Sub Instance Member
Sub Constuctor
另外我们看看下面的代码,说明了静态域先赋default值;然后按顺序赋assign值,先执行tester = new Test(),这时候count1和count2还是0,所以自加后都是1。
private static Test tester = new Test(); private static int count1; private static int count2 = 2; public Test() { count1++; count2++; System.out.println("c1=" +count1 + "; c2=" + count2); }
console:
c1=1; c2=1
时间: 2024-10-11 19:06:13