java解惑(一)之类的初始化
学而不精则淡,精而不用则废。
了解包括继承和static在内的初始化权过程,以对所发生的一切有个全局性的把握,是很有益的。请看下面一个例子:
class Insect { private int i = 0; protected int j; static{ System.out.println("static codes initialized!"); } public Insect() { super(); System.out.println("i=" + i + ",j=" + j); j = 39; } private int x1 = printInit("static Insect.x1 initialized"); int printInit(String s) { System.out.println(s); return 47; } }
public class Beetle extends Insect { private int k = printInit("static Beetle.k initialized"); static{ System.out.println(" Beetle static codes initialized!"); } public Beetle() { super(); System.out.println("k=" + k); System.out.println("j=" + j); } private int x2 = printInit("static Beetle.x2 initialized"); public static void main(String[] args) { System.out.println("Beetle Constructor"); Beetle b = new Beetle(); } }
output
static codes initialized! Beetle static codes initialized! Beetle Constructor static Insect.x1 initialized i=0,j=0 static Beetle.k initialized static Beetle.x2 initialized k=47 j=39
小叶有点想不通为什么会这样子?其实,搞清楚了static和继承对类的加载顺序的影响就懂了。
第一步,Beetle找到主程序路口---main方法,然后找到该类的class文件,发现该类还有个 基类。
第二步:进入Insect类,按照代码书写顺序,加载static代码块,打印出static codes initialized!。
第三步:继续在Insect类中找,发现没有static属性,回到派生类Beetle,加载static代码块,打印出Beetle static codes initialized!(static依赖于类生存的,并且static修饰的代码块或者属性,有且只会加载一次!!!) 第四步:main方法执行,打印Beetle Constructor。第五步:执行到Beetle b = new Beetle(),加载Beetle无参构造方,因为考虑到有继承,会直接进入super(),由于全局变量有默认值的关系,所以打印 static Insect.x1 initialized. i=0,j=0。
第五步:这一步很容易出错,也很关键。当加载完基类的构造器后,程序跳出来不是回到派生类的构造器,而是回到派生类定义属性的地方。加载完类的属性才会再回到构造器加载完余下的部分。打印static Beetle.k initialized,static Beetle.x2 initialized,k=47 j=39
小叶把代码又改了一下:
class Insect { private int i = 0; protected int j; static{ System.out.println("static codes initialized!"); } public Insect() { super(); System.out.println("i=" + i + ",j=" + j); j = 39; } private static int x1 = printInit("static Insect.x1 initialized"); static int printInit(String s) { System.out.println(s); return 47; } }
public class Beetle extends Insect { static{ System.out.println(" Beetle static codes initialized!"); } public Beetle() { super(); System.out.println("k=" + k); System.out.println("j=" + j); } private static int k = printInit("static Beetle.k initialized"); private static int x2 = printInit("static Beetle.x2 initialized"); public static void main(String[] args) { System.out.println("Beetle Constructor"); Beetle b = new Beetle(); } }
跟上面的例子有两个不同:原本的属性使用了static修饰,派生类定义属性的代码放在了构造器代码下面。运行了一下,打印出
static codes initialized! static Insect.x1 initialized Beetle static codes initialized! static Beetle.k initialized static Beetle.x2 initialized Beetle Constructor i=0,j=0 k=47 j=39
你做对了?