亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Java的初始化順序

guqiu / 2228人閱讀

摘要:對子類來講,父類的所有東西都是準(zhǔn)備好的,所以父類部分的初始化要先于子類。父類的初始化順序,遞歸地受以上規(guī)則的控制。例如陳皓的一篇構(gòu)造時(shí)成員初始化的陷阱就談到了一個(gè)讓人頭痛的情況。

需要考慮的”初始化“或者說”調(diào)用“部分就4個(gè):

member

method

特殊的method:constructor。

特殊的member:static member/block。

理解記憶方式:

對多帶帶一個(gè)method來講,它所在的類已經(jīng)被構(gòu)建了,所以它所在類的constructor一定是已經(jīng)被調(diào)用了。(甚至可以展開說,method的被調(diào)用順序是最靠后的,因?yàn)闉榱藢?shí)現(xiàn)多態(tài),它必須要late binding)

對constructor來講,所有的member應(yīng)該都是可用的,所以member的初始化要先于constructor。(成員變量可以看作是這個(gè)類的固有屬性。要構(gòu)建一個(gè)類,它的固有屬性肯定是要事先準(zhǔn)備好。就好比是,你要new一個(gè)desk類,那至少,這個(gè)desk的width, height這些固有屬性要準(zhǔn)備好吧,否則,我怎么知道應(yīng)該建造一個(gè)多大的desk呢?)

對member來講,和所在類息息相關(guān)的static部分,應(yīng)該在定義類的階段,最先就被初始化,所以它會優(yōu)先于其它的member。

【另一方面,要保證所有member準(zhǔn)備好,對于子類來講,可以調(diào)用的父類的member也是應(yīng)該被”正確“準(zhǔn)備好的,而這一條只能由父類的constructor保證。所以父類的constructor要先于子類的member被調(diào)用?!繉ψ宇悂碇v,父類的所有東西都是準(zhǔn)備好的,所以父類部分的初始化要先于子類。所以,父類的constructor要先于子類的member,以保證子類的member調(diào)用的父類public部分都被事先構(gòu)建好了。(但父類的constructor會晚于子類的static,這是一個(gè)例外,見下一條)

由于static是和類一起同生共死,所以,即便是子類,在看到這個(gè)名字時(shí)對應(yīng)的static就已經(jīng)被初始化了,所以它”甚至“優(yōu)先于父類的constructor,但會晚于父類的static(子類的static可能會調(diào)用父類的static,所以必須保證父類的static先被初始化)。

父類的初始化順序,遞歸地受以上規(guī)則的控制。

那是不是說掌握了這些原則就萬事大吉了呢?我想并不是,更重要的是,你需要按照規(guī)范去編寫代碼。

但是,你并不總是可以遇到很規(guī)范的代碼,往往會有奇怪的邏輯和用法。例如陳皓的一篇blog《JAVA構(gòu)造時(shí)成員初始化的陷阱》就談到了一個(gè)讓人頭痛的情況。我們做簡要地考察:

public class Base
{
    Base() {
        preProcess();
    }
 
    void preProcess() {}
}

public class Derived extends Base
{
    public String whenAmISet = "set when declared";
 
    @Override void preProcess()
    {
        whenAmISet = "set in preProcess()";
    }
}

public class Main
{
    public static void main(String[] args)
    {
        Derived d = new Derived();
        System.out.println( d.whenAmISet );
    }
}

問的是,在main()函數(shù)中,whenAmISet的值應(yīng)該是什么。

有了我們上面的分析做基礎(chǔ),我覺得你不應(yīng)該直接去回答這個(gè)問題,而是應(yīng)該反問,這段代碼的邏輯是否有問題。

因?yàn)樵?b>Base這個(gè)類中,構(gòu)造函數(shù)竟然調(diào)用了一個(gè)method來做初始化,而且,這個(gè)method還在子類中被重寫。

通過我們上面的邏輯,method的初始化應(yīng)該放在最后,因?yàn)橐С謑ate binding。就算要做初始化,也該把初始化的method設(shè)定為靜態(tài)。可這里卻反常地使用了一般的method。所以不得不說,這樣編寫代碼的邏輯是否有問題。

再來就可以引述陳皓文中總結(jié)性的話了:

在語言設(shè)計(jì)的時(shí)候,“在構(gòu)造函數(shù)中調(diào)用虛函數(shù)”是個(gè)兩難的問題。

如果調(diào)用的是父類的函數(shù)的話,這個(gè)有點(diǎn)違反虛函數(shù)的定義。

如果調(diào)用的是子類的函數(shù)的話,這可能產(chǎn)生問題的:因?yàn)樵跇?gòu)造子類對象的時(shí)候,首先調(diào)用父類的構(gòu)造函數(shù),而這時(shí)候如果去調(diào)用子類的函數(shù),由于子類還沒有構(gòu)造完成,子類的成員尚未初始化,這么做顯然是不安全的。

C++選擇了第一種,而Java選擇了第二種。

無論是哪一種,這種用法本身其實(shí)就是有問題的。我想,除了應(yīng)付面試、考試,這樣的編寫方式就不應(yīng)該讓它存在。而不是反過來,去鉆研它為什么是對的。這只不過是拿更多的錯(cuò)誤去掩蓋已成事實(shí)的錯(cuò)誤。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/77095.html

相關(guān)文章

  • Java始化順序

    摘要:對子類成員數(shù)據(jù)按照它們聲明的順序初始化,執(zhí)行子類構(gòu)造函數(shù)的其余部分。參考類的初始化順序引了大半類加載的時(shí)機(jī) jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card table數(shù)據(jù)結(jié)構(gòu) Java類初始化順序 Java對象結(jié)構(gòu)及大小計(jì)算 Java的類加載機(jī)制 Java對象分配簡要流程 年老...

    boredream 評論0 收藏0
  • java入門第二季--繼承--java繼承始化順序

    摘要:中的繼承初始化順序父類和子類年齡動(dòng)物可以吃東西類執(zhí)行了年齡狗可以吃東西類執(zhí)行了對象的屬性和構(gòu)造方法年齡動(dòng)物可以吃東西類執(zhí)行了的 java中的繼承初始化順序 showImg(https://segmentfault.com/img/bVbnBI1?w=1277&h=671); showImg(https://segmentfault.com/img/bVbnBKG?w=811&h=427...

    CoorChice 評論0 收藏0
  • Java集合之LinkedHashMap源碼解析

    摘要:底層基于拉鏈?zhǔn)降纳⒘薪Y(jié)構(gòu),并在中引入紅黑樹優(yōu)化過長鏈表的問題。在其之上,通過維護(hù)一條雙向鏈表,實(shí)現(xiàn)了散列數(shù)據(jù)結(jié)構(gòu)的有序遍歷。 原文地址 LinkedHashMap LinkedHashMap繼承自HashMap實(shí)現(xiàn)了Map接口?;緦?shí)現(xiàn)同HashMap一樣,不同之處在于LinkedHashMap保證了迭代的有序性。其內(nèi)部維護(hù)了一個(gè)雙向鏈表,解決了 HashMap不能隨時(shí)保持遍歷順序和插...

    QiShare 評論0 收藏0
  • Java 多態(tài)(8)

    摘要:在面向?qū)ο蟮某绦蛟O(shè)計(jì)語言中,多態(tài)是繼數(shù)據(jù)抽象和繼承之后的第三種基本特征。 在面向?qū)ο蟮某绦蛟O(shè)計(jì)語言中,多態(tài)是繼數(shù)據(jù)抽象和繼承之后的第三種基本特征。 1.再論向上轉(zhuǎn)型 多態(tài)作用:消除類型之間的耦合關(guān)系. 2.轉(zhuǎn)機(jī) 綁定:將一個(gè)方法調(diào)用同一個(gè)方法主體關(guān)聯(lián)起來. 前期綁定:在程序執(zhí)行前就進(jìn)行綁定(面向過程語言默認(rèn)綁定方式). 后期綁定:也叫動(dòng)態(tài)綁定或運(yùn)行時(shí)綁定,在運(yùn)行時(shí)根據(jù)對象的類型進(jìn)行綁...

    v1 評論0 收藏0
  • 談?wù)?em>Java面向?qū)ο?/b>

    摘要:也就是說,一個(gè)實(shí)例變量,在的對象初始化過程中,最多可以被初始化次。當(dāng)所有必要的類都已經(jīng)裝載結(jié)束,開始執(zhí)行方法體,并用創(chuàng)建對象。對子類成員數(shù)據(jù)按照它們聲明的順序初始化,執(zhí)行子類構(gòu)造函數(shù)的其余部分。 類的拷貝和構(gòu)造 C++是默認(rèn)具有拷貝語義的,對于沒有拷貝運(yùn)算符和拷貝構(gòu)造函數(shù)的類,可以直接進(jìn)行二進(jìn)制拷貝,但是Java并不天生支持深拷貝,它的拷貝只是拷貝在堆上的地址,不同的變量引用的是堆上的...

    ormsf 評論0 收藏0
  • Java對象始化順序

    摘要:初始化順序有無父類有將父類加載進(jìn)內(nèi)存。如果有初始化子類對象。初始化完畢之后,再執(zhí)行構(gòu)造器內(nèi)的方法。初始化完父類后,依次初始化子類的。 初始化順序:1.有無父類?有:將父類加載進(jìn)內(nèi)存。直到將所有的父類加載完畢。再從頂層父類按照代碼的順序執(zhí)行靜態(tài)代碼,執(zhí)行完最頂層的,在執(zhí)行下一層的,依次類推,直到執(zhí)行完所有的靜態(tài)代碼。(1)如果有初始化子類對象。那么同樣會先調(diào)用父類的構(gòu)造器,并且會先執(zhí)行最...

    incredible 評論0 收藏0

發(fā)表評論

0條評論

guqiu

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<