【正文】
編譯器會(huì)加上代碼,如下: public class TestConstructors { TestConstructors() { super。 } } 仔細(xì)想一下,就知道下面的代碼 public class Example {} 經(jīng)過(guò)會(huì)被編譯器加代碼形如: public class Example { Example() { super。 } } 繼承 構(gòu)造器是不能被繼承的。子類(lèi)可以繼承超類(lèi)的任何方法。看看下面的代碼: public class Example { public void sayHi { (Hi)。 } Example() {} } public class SubClass extends Example { } 類(lèi) SubClass 自動(dòng)繼承了父類(lèi)中的sayHi方法,但是,父類(lèi)中的構(gòu)造器 Example()卻不能被繼承。 以下在構(gòu)造器 里構(gòu)造器自己是不對(duì)的public test() { s = new test()。}異常:xception in thread main at .init(:15)at .init(:15)at .init(:15)at .init(:15).........還要學(xué)會(huì)修飾符的應(yīng)用后,本類(lèi)的范圍.構(gòu)造方法的初始化順序 想像一下你正在用java寫(xiě)程序,并且用下面的代碼初始化類(lèi) A 和 B 的對(duì)象:class A {int a = f()。int f() {return 1。}}class B extends A {int b = a。int f() {return 2。}}public class CtorDemo1 {public static void main(String args[]) {B bobj = new B()。()。}}現(xiàn)在,好像很明顯的當(dāng)初始化完成后。畢竟,類(lèi)B中的b 的值是用類(lèi)A中的a的值初始化的,而a 是用f 的值初始化的,而它的值為1,對(duì)嗎?實(shí)際上, 的值是2,要知道為什么需要知道對(duì)象初始化的問(wèn)題。當(dāng)一個(gè)對(duì)象被創(chuàng)建時(shí),初始化是以下面的順序完成的:1. 設(shè)置成員的值為缺省的初始值 (0, false, null)2. 調(diào)用對(duì)象的構(gòu)造方法 (但是還沒(méi)有執(zhí)行構(gòu)造方法體)3. 調(diào)用父類(lèi)的構(gòu)造方法4. 使用初始化程序和初始?jí)K初始化成員5. 執(zhí)行構(gòu)造方法體看看在實(shí)際中是如何一步一步完成的,看看下面的例子:class A {A() {( called)。}}class B extends A {int i = f()。int j。{j = 37。(initialization block executed)。}B() {( called)。}int f() {( called)。return 47。}}public class CtorDemo2 {public static void main(String args[]) {B bobj = new B()。}}程序的輸出是: called calledinitialization block executed calledB 的構(gòu)造方法被調(diào)用,但是最先做的事情是隱含的調(diào)用父類(lèi)的構(gòu)造方法。父類(lèi)必須自己負(fù)責(zé)初始化它自己的狀態(tài)而不是讓子類(lèi)來(lái)做。然后B對(duì)象的成員被初始化, 的調(diào)用和包圍在{}中的初始?jí)K的執(zhí)行。最后B的構(gòu)造方法體被執(zhí)行。你可能會(huì)問(wèn)“什么是對(duì)父類(lèi)的構(gòu)造方法的隱含調(diào)用”。這意味著如果你的構(gòu)造方法的第一行不是下面內(nèi)容之一:super()。super(args)。this()。this(args)。則有下面的調(diào)用:super()。提供給構(gòu)造方法的第一行。如果類(lèi)沒(méi)有構(gòu)造方法呢?在這種情況下,一個(gè)缺省的構(gòu)造方法(也叫無(wú)參構(gòu)造方法)由java編譯器自動(dòng)生成。缺省構(gòu)造方法只有在類(lèi)沒(méi)有任何其它的構(gòu)造方法時(shí)才產(chǎn)生。更深入的明白這個(gè),:public class A {public static void main(String args[]) {A aref = new A()。}} 中的字節(jié)碼,輸入下面的內(nèi)容:$ javac $ javap c classpath . A輸出:Compiled from public class A extends {public A()。public static void main([])。}Method A()0 aload_01 invokespecial 14 returnMethod void main([])0 new 23 dup4 invokespecial 37 astore_18 return在main 中,注意對(duì) A 的構(gòu)造方法的調(diào)用(就是invokespecial 行),以及A的構(gòu)造方法中產(chǎn)生的類(lèi)似的對(duì)Object 構(gòu)造方法的調(diào)用。如果父類(lèi)沒(méi)有缺省構(gòu)造方法,你必須明確使用super(args)調(diào)用父類(lèi)的某個(gè)構(gòu)造方法,例如,下面是一個(gè)錯(cuò)誤的用法:class A {A(int i) {}}class B extends A {}在上面的情況下, A 沒(méi)有缺省的構(gòu)造方法,但是B的構(gòu)造方法必須調(diào)用A的某個(gè)構(gòu)造方法。讓我們來(lái)看看初始化的另一個(gè)例子:class A {A() {( called)。}A(int i) {this()。((int) called)。}}class B extends A {int i = f()。int j。{j = 37。(initialization block executed)。}B() {this(10)。(() called)。}B(int i) {super(i)。((int) called)。}int f() {( called)。return 47。}}public class CtorDemo3 {public static void main(String args[]) {B bobj = new B()。}}程序的輸出是: called(int) called calledinitialization block executed(int) called() called這個(gè)例子明確使用super() 和 this() 調(diào)用。this()調(diào)用是調(diào)用同一個(gè)類(lèi)中的另一個(gè)構(gòu)造方法;這個(gè)方法被稱(chēng)為“顯式構(gòu)造方法調(diào)用”。當(dāng)那樣的構(gòu)造方法被調(diào)用,它將執(zhí)行通常的super() 過(guò)程以及后續(xù)的操作。 (int)之前執(zhí)行,(int) 前執(zhí)行。如果返回第一個(gè)例子,你就可以回答為什么打印的是2而不是1。B 沒(méi)有構(gòu)造方法,因此生成一個(gè)缺省構(gòu)造方法,然后它調(diào)用super(),然后調(diào)用A 產(chǎn)生的缺省構(gòu)造方法。然后A中的成員被初始化,成員a 被設(shè)置為方法f()的值,但是因?yàn)锽 對(duì)象正被初始化,f() 返回值2。換句話說(shuō),調(diào)用的是B中的f()方法。A產(chǎn)生的構(gòu)造方法體被執(zhí)行,然后B的成員被初始化,而b 被賦予值a,也就是2。最后,B的構(gòu)造方法被執(zhí)行。最后一個(gè)例子說(shuō)明了第一個(gè)例子的一個(gè)小小的變異版本:class A {int a = f()。int f() {return 1。}}class B extends A {int b = 37。int f() {return b。}}public class CtorDemo4 {public static void main(String args[]) {B bobj = new B()。()。(())。}}程序的輸出是:037 ()是一樣的,但是正如你看到的他們不一樣。這是正確的,即使是在a是從B的f方法中初始化的并且打印的是a 和 B的 f 方法的值。這兒的問(wèn)題是當(dāng)a通過(guò)對(duì)B的f方法調(diào)用而初始化,而該方法返回成員b的值,而該成員還沒(méi)有被初始化。因?yàn)檫@個(gè),b的值就是剛開(kāi)始的初始值0。這些例子解釋了編程中重要的一點(diǎn)――在對(duì)象的構(gòu)造階段調(diào)用可重載的方法是不明智的。 父類(lèi)的成員變量的初始化值〉如果初始化成員變量時(shí)要調(diào)用父類(lèi)的方法(如private int a=getData()。),就會(huì)執(zhí)行此父類(lèi)的方法. 但是如果此方法被子類(lèi)覆蓋,那么這里是調(diào)用子類(lèi)的方法(getData())。執(zhí)行父類(lèi)的構(gòu)造函數(shù)子類(lèi)的成員變量的初始化值 〉執(zhí)行子類(lèi)的構(gòu)造函數(shù)。 技巧:其實(shí)繼承就是可以把子父類(lèi)按規(guī)定的順序組合起來(lái)。先是父類(lèi)的屬性在前,在是子類(lèi)的屬性,再是父類(lèi)的構(gòu)造方法,再是子類(lèi)的構(gòu)造方法,再是父類(lèi)與子類(lèi)的方法,如果方法有覆蓋的,用子類(lèi)的。注意順序。錯(cuò)錯(cuò).........錯(cuò)了...20080123 修正:初始化 順序應(yīng)該是.父靜態(tài)變量子靜態(tài)變量父非靜態(tài)變量父靜態(tài)代碼塊父構(gòu)造函數(shù)子非變量子靜態(tài)代碼塊子構(gòu)造函數(shù)