誰是狸貓誰是太子?--戲說java構造器
故事背景
《狸貓換太子》在我國民間文學中很出名,故事劇情大致如下:北宋第三位皇帝宋真宗趙恆年長無子,他的兩個妃子劉妃與李妃同時懷了身孕。真宗召見二人,各賜信物,並宣告哪個生了兒子就立誰為皇后。生性陰險的劉妃在太監郭槐的幫助下,把李妃生下的孩子換成了剝了皮的狸貓,命承禦寇珠將孩子拋人九曲橋下淹死。
寇珠不忍,求計於太監陳琳,將太子藏入妝盒,密送八賢王趙德芳處撫養。劉妃誣告李妃產下妖摩,於是真宗將李妃貶入冷宮,冊封劉妃為皇后。郭槐告發寇珠與陳琳在九曲橋私會,劉皇后命陳琳拷問寇珠,寇珠不屈,觸柱而亡。劉皇后又命郭槐火燒冷官,李妃被內監救出,流落民間。
18年後,真宗死,李妃之子趙禎即位為仁宗,包拯至陳州賑濟,李妃鳴冤,包拯受狀查明沉冤。仁宗斬郭槐,貶劉大後,迎母親回官,母子團聚,“狸貓換太子”真相大自。
java之狸貓太子
我們假定正確的構造方法在java中為太子,假的構造方法為狸貓,那我們看一下下面的程式會打印出什麼結果吧?
public class ConstructorTest { static { System.out.println("who is prince? "); } public void ConstructorTest() { System.out.println("i am prince!"); } public void getName() { System.out.println("i am not prince"); } public static void main(String[] args) { ConstructorTest test=new ConstructorTest(); test.getName(); } }
我們本來想打印出太子:
who is prince?
i am prince
真實執行打印出的卻是狸貓:
who is prince?
i am not prince
那到底是什麼一回事呢?
原來是皇帝受奸臣void 矇蔽了,將真假太子弄錯了。
太監void後面的不是太子(構造器),而是普通方法,在main方法中並沒呼叫該方法,而由於沒有任何宣告的構造器,所以編譯器會幫助(真的是在幫忙嗎?)生成一個公共的無引數構造器,它除了初始化它所建立的域例項之外,不做任何事情。
java之太子之爭
因構造方法可以有多個,就會產生太子之爭,那麼怎麼識別誰才是真正的太子呢?
public class Confusing { private Confusing(Object o) { System.out.println("Object"); } private Confusing(double[] dArray) { System.out.println("double array"); } public static void main(String[] args) { new Confusing(null); } }
上面的題目給你了兩個容易令人混淆的構造器。main 方法呼叫了一個構造器,但是它呼叫的到底是哪一個呢?該程式的輸出取決於這個問題的答案。那麼它到底會打印出什麼呢?甚至它是否是合法的呢?
Java 的方法(包括構造器方法)觸發過程是以兩階段執行的。第一階段選取所有可獲得並且可應用的方法或構造器。第二階段在第一階段選取的方法或構造器中選取最精確的一個。如果一個方法或構造器可以接受傳遞給另一個方法或構造器的任何引數,那麼我們就說第一個方法比第二個方法缺乏精確性[JLS 15.12.2.5]
在我們的程式中,兩個構造器都是可獲得並且可應用的。構造器Confusing(Object)可以接受任何傳遞給Confusing(double[ ])的引數,因此Confusing(Object)相對缺乏精確性。(每一個double 陣列都是一個Object,但是每一個Object 並不一定是一個double 陣列。)因此,最精確的構造器就是
Confusing(double[ ])。故結果是:double array
參考資料
【1】https://baijiahao.baidu.com/s?id=1613952761238601257&wfr=spider&for=pc
【2】https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.12
【3】java