亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java初始化和實例化順序

Java初始化和實例化順序

翻閱古今 2019-07-15 16:52:54
Java初始化和實例化順序我試圖將JVM中的初始化和實例化過程拼湊在一起,但是JLS在一些細節上有點遲鈍,所以如果有人介意澄清一些細節,我們將不勝感激。到目前為止,這就是我所能找到的。初始化遞歸初始化類的靜態最終變量及其編譯時間常數的接口。退出遞歸,按文本順序處理靜態塊和靜態字段。實例化遞歸初始化編譯時間常數的類的最終實例變量。退出遞歸處理,按文本順序處理非靜態塊和實例字段,在返回時將它們放在構造函數的前面。好了,現在開始提問。接口是否按聲明順序處理?接口是否在單獨的遞歸堆棧中處理?如果是,是否在超類之前或之后處理接口?(B)如果是,我是否正確地推斷其中一個或另一個(Interface或Superclass)在其他編譯時常量之前初始化了它的非編譯時常數字段。在這個過程中,調用非默認的超級()構造函數扮演什么角色?我的結論有錯嗎?我有沒有遺漏其他關鍵細節?
查看完整描述

2 回答

?
慕標5832272

TA貢獻1966條經驗 獲得超4個贊

區分類的初始化和對象的初始化非常重要。

類初始化

初始化類或接口。第一次訪問,通過分配編譯時間常數字段,然后遞歸初始化超類(如果尚未初始化),然后處理靜態初始化器(其中包括非編譯時間常數的靜態字段的初始化程序)。

正如您已經注意到的,類的初始化本身并不會觸發它實現的接口的初始化。因此,接口在第一次訪問時被初始化,通常是通過讀取非編譯時間常數的字段進行初始化。..此訪問可能發生在初始化器的計算過程中,從而導致遞歸初始化。

還值得注意的是,初始化不是通過訪問作為編譯時間常量的字段來觸發的,因為這些字段是在編譯時間:

對常量變量(§4.12.4)的字段的引用必須在編譯時解析為由常量變量的初始化器表示的值V。

如果這樣的字段是靜態的,那么在二進制文件中的代碼中不應該存在對該字段的引用,包括聲明該字段的類或接口。這樣的字段必須始終看起來已經初始化(§12.4.2);字段的缺省初始值(如果與V不同)絕不能被觀察到。

如果這樣的字段是非靜態的,那么除了包含字段的類之外,二進制文件中的代碼中不應該存在對字段的引用。(它將是一個類,而不是一個接口,因為接口只有靜態字段。)類應該有代碼,以便在實例創建期間將字段的值設置為V(§12.5)。

對象初始化

對象被初始化。每當創建新對象時,通常通過計算類實例創建表達式。這方面的進展如下:

  1. 將構造函數的參數分配給此構造函數調用的新創建的參數變量。

  2. 如果該構造函數以同一個類中的另一個構造函數的顯式構造函數調用(§8.8.7.1)開始(使用此方法),則使用這五個步驟遞歸地計算參數和處理構造函數調用。如果構造函數調用突然完成,則此過程出于同樣的原因突然完成;否則,繼續執行步驟5。

  3. 此構造函數不以同一類中的另一個構造函數的顯式構造函數調用開始(使用此方法)。如果此構造函數用于對象以外的類,則此構造函數將以超類構造函數的顯式或隱式調用(使用超級)開始。使用這五個步驟遞歸地評估超類構造函數調用的參數和過程。如果構造函數調用突然完成,則此過程出于同樣的原因突然完成。否則,繼續執行步驟4。

  4. 為該類執行實例初始化器和實例變量初始化器,將實例變量初始化器的值按從左到右的順序分配給相應的實例變量,這些變量在類的源代碼中以文本形式出現。如果執行這些初始化程序中的任何一個都會導致異常,那么將不再處理其他初始化器,并且該過程在相同的異常下突然完成。否則,繼續執行步驟5。

  5. 執行此構造函數主體的其余部分。如果該執行突然完成,則此過程出于同樣的原因突然完成。否則,此過程將正常完成。

正如我們在步驟3中所看到的,對超級構造函數的顯式調用的存在只是改變了調用哪個超類構造函數。


查看完整回答
反對 回復 2019-07-15
?
天涯盡頭無女友

TA貢獻1831條經驗 獲得超9個贊

下面是一個在對象創建過程中打印每個步驟順序的示例。

java:

import javax.annotation.PostConstruct;/**
 * Test steps of instance creation.
 * 
 * @author eric
 * @date Jan 7, 2018 3:31:12 AM
 */public class InstanceCreateStepTest {
    public static void main(String[] args) {
        new Sub().hello();
        System.out.printf("%s\n", "------------");
        new Sub().hello();
    }}class Base {
    static {
        System.out.printf("%s - %s - %s\n", "base", "static", "block");
    }
    {
        System.out.printf("%s - %s - %s\n", "base", "instance", "block");
    }

    public Base() {
        System.out.printf("%s - %s\n", "base", "constructor");
    }

    @PostConstruct
    public void init() {
        System.out.printf("%s - %s\n", "base", "PostConstruct");
    }

    public void hello() {
        System.out.printf("%s - %s\n", "base", "method");
    }}class Sub extends Base {
    static {
        System.out.printf("%s - %s - %s\n", "sub", "static", "block");
    }
    {
        System.out.printf("%s - %s - %s\n", "sub", "instance", "block");
    }

    public Sub() {
        System.out.printf("%s - %s\n", "sub", "constructor");
    }

    @PostConstruct
    public void init() {
        System.out.printf("%s - %s\n", "sub", "PostConstruct");
    }

    @Override
    public void hello() {
        // super.hello();
        System.out.printf("%s - %s\n", "sub", "method");
    }}

處決:

只需調用main方法,然后檢查輸出。

小貼士:

  • 標記的方法

    @PostConstruct

    不會被調用,除非您在某個容器中調用它,例如

    Spring-boot

    ,因為它依賴于那些容器來實現注釋,如

    @PostConstruct.


查看完整回答
反對 回復 2019-07-15
  • 2 回答
  • 0 關注
  • 877 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號