Java提高篇——靜態代碼塊、構造代碼塊、構造函數以及Java類初始化順序

来源:http://www.cnblogs.com/Qian123/archive/2016/07/28/5713440.html
-Advertisement-
Play Games

靜態代碼塊:用staitc聲明,jvm載入類時執行,僅執行一次構造代碼塊:類中直接用{}定義,每一次創建對象時執行。執行順序優先順序:靜態塊,main(),構造塊,構造方法。 構造函數 關於構造函數,以下幾點要註意:1.對象一建立,就會調用與之相應的構造函數,也就是說,不建立對象,構造函數時不會運行的 ...


靜態代碼塊:用staitc聲明,jvm載入類時執行,僅執行一次
構造代碼塊:類中直接用{}定義,每一次創建對象時執行。
執行順序優先順序:靜態塊,main(),構造塊,構造方法。

構造函數

public HelloA(){//構造函數
    }

關於構造函數,以下幾點要註意:
1.對象一建立,就會調用與之相應的構造函數,也就是說,不建立對象,構造函數時不會運行的。
2.構造函數的作用是用於給對象進行初始化。
3.一個對象建立,構造函數只運行一次,而一般方法可以被該對象調用多次。

構造代碼塊

{//構造代碼塊    
}

關於構造代碼塊,以下幾點要註意:

  1. 構造代碼塊的作用是給對象進行初始化。
  2. 對象一建立就運行構造代碼塊了,而且優先於構造函數執行。這裡要強調一下,有對象建立,才會運行構造代碼塊,類不能調用構造代碼塊的,而且構造代碼塊與構造函數的執行順序是前者先於後者執行
  3. 構造代碼塊與構造函數的區別是:構造代碼塊是給所有對象進行統一初始化,而構造函數是給對應的對象初始化,因為構造函數是可以多個的,運行哪個構造函數就會建立什麼樣的對象,但無論建立哪個對象,都會先執行相同的構造代碼塊。也就是說,構造代碼塊中定義的是不同對象共性的初始化內容。

靜態代碼塊

static {//靜態代碼塊    
}

關於靜態代碼塊,要註意的是:

  1. 它是隨著類的載入而執行,只執行一次,並優先於主函數。具體說,靜態代碼塊是由類調用的。類調用時,先執行靜態代碼塊,然後才執行主函數的。
  2. 靜態代碼塊其實就是給類初始化的,而構造代碼塊是給對象初始化的
  3. 靜態代碼塊中的變數是局部變數,與普通函數中的局部變數性質沒有區別。
  4. 一個類中可以有多個靜態代碼塊
public class Test{
staitc int cnt=6;
static{
      cnt+=9;
}
public static void main(String[] args) {
      System.out.println(cnt);
}
static{
      cnt/=3;
}
}
運行結果:
5

Java類初始化順序

## 對於一個類的情況

例子1:

public class HelloA {
    public HelloA(){//構造函數
        System.out.println("A的構造函數");    
    }
    {//構造代碼塊
        System.out.println("A的構造代碼塊");    
    }
    static {//靜態代碼塊
        System.out.println("A的靜態代碼塊");        
    }
    public static void main(String[] args) {
    }
}
運行結果:
A的靜態代碼塊

例子2:

public class HelloA {
    public HelloA(){//構造函數
        System.out.println("A的構造函數");    
    }
    {//構造代碼塊
        System.out.println("A的構造代碼塊");    
    }
    static {//靜態代碼塊
        System.out.println("A的靜態代碼塊");        
    }
    public static void main(String[] args) {
        HelloA a=new HelloA();    
    }
}

運行結果:
A的靜態代碼塊
A的構造代碼塊
A的構造函數

例子3:

public class HelloA {
    public HelloA(){//構造函數
        System.out.println("A的構造函數");    
    }
    {//構造代碼塊
        System.out.println("A的構造代碼塊");    
    }
    static {//靜態代碼塊
        System.out.println("A的靜態代碼塊");        
    }
    public static void main(String[] args) {
        HelloA a=new HelloA();
        HelloA b=new HelloA();
    }

}

運行結果:
A的靜態代碼塊
A的構造代碼塊
A的構造函數
A的構造代碼塊
A的構造函數

對於一個類而言,按照如下順序執行:

  1. 執行靜態代碼塊
  2. 執行構造代碼塊
  3. 執行構造函數

對於靜態變數、靜態初始化塊、變數、初始化塊、構造器,它們的初始化順序依次是(靜態變數、靜態初始化塊)>(變數、初始化塊)>構造器。

例子4:

 1 public class InitialOrderTest {
 2         /* 靜態變數 */
 3     public static String staticField = "靜態變數";
 4         /* 變數 */
 5     public String field = "變數";
 6         /* 靜態初始化塊 */
 7     static {
 8         System.out.println( staticField );
 9         System.out.println( "靜態初始化塊" );
10     }
11         /* 初始化塊 */
12     {
13         System.out.println( field );
14         System.out.println( "初始化塊" );
15     }
16         /* 構造器 */
17     public InitialOrderTest()
18     {
19         System.out.println( "構造器" );
20     }
21 
22 
23     public static void main( String[] args )
24     {
25         new InitialOrderTest();
26     }
27 }

運行以上代碼,我們會得到如下的輸出結果:

  1. 靜態變數

  2. 靜態初始化塊

  3. 變數

  4. 初始化塊

  5. 構造器

## 對於繼承情況

例子5:

public class HelloA {
    public HelloA(){//構造函數
        System.out.println("A的構造函數");    
    }
    {//構造代碼塊
        System.out.println("A的構造代碼塊");    
    }
    static {//靜態代碼塊
        System.out.println("A的靜態代碼塊");        
    }
}
public class HelloB extends HelloA{
    public HelloB(){//構造函數
        System.out.println("B的構造函數");    
    }
    {//構造代碼塊
        System.out.println("B的構造代碼塊");    
    }
    static {//靜態代碼塊
        System.out.println("B的靜態代碼塊");        
    }
    public static void main(String[] args) {
        HelloB b=new HelloB();        
    }
}
運行結果:
A的靜態代碼塊
B的靜態代碼塊
A的構造代碼塊
A的構造函數
B的構造代碼塊
B的構造函數

當涉及到繼承時,按照如下順序執行:

  1. 執行父類的靜態代碼塊,並初始化父類靜態成員變數
  2. 執行子類的靜態代碼塊,並初始化子類靜態成員變數
  3. 執行父類的構造代碼塊,執行父類的構造函數,並初始化父類普通成員變數
  4. 執行子類的構造代碼塊, 執行子類的構造函數,並初始化子類普通成員變數

例子6:

 1 class Parent {
 2         /* 靜態變數 */
 3     public static String p_StaticField = "父類--靜態變數";
 4          /* 變數 */
 5     public String    p_Field = "父類--變數";
 6     protected int    i    = 9;
 7     protected int    j    = 0;
 8         /* 靜態初始化塊 */
 9     static {
10         System.out.println( p_StaticField );
11         System.out.println( "父類--靜態初始化塊" );
12     }
13         /* 初始化塊 */
14     {
15         System.out.println( p_Field );
16         System.out.println( "父類--初始化塊" );
17     }
18         /* 構造器 */
19     public Parent()
20     {
21         System.out.println( "父類--構造器" );
22         System.out.println( "i=" + i + ", j=" + j );
23         j = 20;
24     }
25 }
26 
27 public class SubClass extends Parent {
28          /* 靜態變數 */
29     public static String s_StaticField = "子類--靜態變數";
30          /* 變數 */
31     public String s_Field = "子類--變數";
32         /* 靜態初始化塊 */
33     static {
34         System.out.println( s_StaticField );
35         System.out.println( "子類--靜態初始化塊" );
36     }
37        /* 初始化塊 */
38     {
39         System.out.println( s_Field );
40         System.out.println( "子類--初始化塊" );
41     }
42        /* 構造器 */
43     public SubClass()
44     {
45         System.out.println( "子類--構造器" );
46         System.out.println( "i=" + i + ",j=" + j );
47     }
48 
49 
50         /* 程式入口 */
51     public static void main( String[] args )
52     {
53         System.out.println( "子類main方法" );
54         new SubClass();
55     }
56 }

結果:

父類--靜態變數
父類--靜態初始化塊
子類--靜態變數
子類--靜態初始化塊
子類main方法
父類--變數
父類--初始化塊
父類--構造器
i=9, j=0
子類--變數
子類--初始化塊
子類--構造器
i=9,j=20

子類的靜態變數和靜態初始化塊的初始化是在父類的變數、初始化塊和構造器初始化之前就完成了。靜態變數、靜態初始化塊,變數、初始化塊初始化了順序取決於它們在類中出現的先後順序。

### 分析

  • (1)訪問SubClass.main(),(這是一個static方法),於是裝載器就會為你尋找已經編譯的SubClass類的代碼(也就是SubClass.class文件)。在裝載的過程中,裝載器註意到它有一個基類(也就是extends所要表示的意思),於是它再裝載基類。不管你創不創建基類對象,這個過程總會發生。如果基類還有基類,那麼第二個基類也會被裝載,依此類推。

  • (2)執行根基類的static初始化,然後是下一個派生類的static初始化,依此類推。這個順序非常重要,因為派生類的“static初始化”有可能要依賴基類成員的正確初始化。

  • (3)當所有必要的類都已經裝載結束,開始執行main()方法體,並用new SubClass()創建對象。

  • (4)類SubClass存在父類,則調用父類的構造函數,你可以使用super來指定調用哪個構造函數。基類的構造過程以及構造順序,同派生類的相同。首先基類中各個變數按照字面順序進行初始化,然後執行基類的構造函數的其餘部分。

  • (5)對子類成員數據按照它們聲明的順序初始化,執行子類構造函數的其餘部分。


參考文章鏈接:

java-靜態代碼塊,構造代碼塊,構造函數

Java類初始化順序

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載爬蟲請註明地址,博客園蝸牛 http://www.cnblogs.com/tdws/p/5712835.html 先配上一個簡易的RedisHelper,一個set值,一個get值,一個設置併發鎖,以便在我後面的操作中,你能清楚我究竟做了什麼。 1 public class RedisHelpe ...
  • 隨機數在現代社會應用不可謂少,我們可以在每天用到的手機驗證碼,網上博彩,網上鬥地主等等 中看到隨機數的影子 隨機數在現代社會應用不可謂少,我們可以在每天用到的手機驗證碼,網上博彩,網上鬥地主等等 中看到隨機數的影子 7月27日晚9點,學習之餘在如鵬網楊中科視頻中便看到關於隨機數的解釋http://w ...
  • 要求說明: 通過網站上傳文件保存到統一的文件伺服器上。 伺服器說明: 1.文件伺服器以下稱為FilesServer,IP地址為:192.168.1.213 2.Web伺服器為以下稱為WebServer,IP地址為:192.168.1.214 詳細步驟: (1)在FilesServer和WebServ ...
  • //頁面初期載入時 $(document).ready(function () { //載入第一頁 LoadList(); //滾動換頁 $(window).scroll(function () { //向上翻頁判定 if ($(document).scrollTop() <= $(window). ...
  • 主要封裝了關於數據載入時的彈框提示,以及自動彈框提示後關閉功能和右下角動態彈出後緩慢退出功能(有點想網吧提示餘額不足的情況),方便以後直接使用。這個不解釋,只要用winform開發,絕對會用到。節約開發時間 ...
  • 由於業務需求,最近將項目部分模塊修改為偽靜態,使用到了Intelligencia.UrlRewriter.dll組件。 網上對使用Intelligencia.UrlRewriter.dll的配置講解很多,在此就不多說了,(如:http://www.cnblogs.com/naoguazi/p/URL ...
  • 一、前言 說來慚愧,做了幾年ASP.NET最近才有機會使用MVC開發生產項目。項目中新增、編輯表單提交存在大量服務端數據格式校驗,各種if else顯得代碼過於繁瑣,特別是表單數據比較多的時候尤為噁心,正好今天比較閑就寫了一個Demo,統一驗證Model層中的數據格式。在此說明一下,MVC自帶數據檢 ...
  • myeclipse老版本不分32位和64位,歡迎大家下載使用! 鏈接:http://pan.baidu.com/s/1dEJCxcl 密碼:z1ga ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...