前言
複習下Java中的靜態代碼塊、構造代碼塊、構造函數、普通代碼塊
正文
概念介紹
1、靜態代碼塊
定義:在類中使用static關鍵字聲明的代碼塊。靜態塊用於初始化類,爲類的屬性初始化。每個靜態代碼塊只會執行一次。由於JVM在加載類時會執行靜態代碼塊,所以靜態代碼塊先於主方法執行。
注意點
- 靜態代碼塊在類被加載的時候就運行了,而且只運行一次,並且優先於各種代碼塊以及構造函數。如果一個類中有多個靜態代碼塊,會按照書寫順序依次執行。
- 靜態代碼塊不能存在任何方法體中。因爲非靜態普通方法是通過加載類,然後new出實例化對象,通過對象才能調用這個方法,而靜態代碼塊只需要加載類之後就能運行了。而對於靜態方法,在類加載的時候,靜態方法也已經加載了,但是我們必須要通過類名或者對象名才能訪問,也就是說靜態代碼塊是主動運行的,而靜態方法是被動運行的。
- 靜態代碼塊不能直接訪問實例變量和實例方法
2、構造代碼塊
定義:直接在類中定義且沒有加static關鍵字的代碼塊稱爲構造代碼塊。構造代碼塊在創建對象時被調用,每次創建對象都會被調用,並且構造代碼塊的執行次序優先於類構造函數。如果存在多個構造代碼塊,執行順序由他們在代碼中出現的次序決定,先出現先執行。
3、普通代碼塊
普通代碼塊和構造代碼塊的區別是,構造代碼塊是在類中定義的,而普通代碼塊是在方法體中定義的。且普通代碼塊的執行順序和書寫順序一致。
4、構造函數
注意點
- 構造函數的命名必須和類名完全相同。在java中普通函數可以和構造函數同名,但是必須帶有返回值;
- 構造函數的功能主要用於在類的對象創建時定義初始化的狀態。它沒有返回值,也不能用void來修飾。
- 構造函數不能被直接調用,必須通過new運算符在創建對象時纔會自動調用;而一般的方法是在程序執行到它的時候被調用的;
- 當定義一個類的時候,通常情況下都會顯示該類的構造函數,並在函數中指定初始化的工作也可省略,不過Java編譯器會提供一個默認的構造函數,此默認構造函數是不帶參數的。
實例測試
CodeBlock類代碼如下:
/**
* Copyright (C), 2015-2020
* FileName: CodeBlock
* Author: niko
* Date: 2020/6/23 11:08
* Description: 測試各種代碼塊
* History:
* <author> <time> <version>
* 逝不等琴生 11:08 1.0
*/
package com.nzc.codeblock;
public class CodeBlock {
static {
System.out.println("我是靜態代碼塊——靜態代碼塊在類被加載的時候就運行了,而且只運行一次,並且優先於各種代碼塊以及構造函數");
}
{
System.out.println("我是構造代碼塊——優先於構造函數執行,每次創建一個對象都執行一次");
}
public CodeBlock() {
System.out.println("我是構造函數——每創建一個對象就執行一次");
}
public void normalFunction() {
System.out.println("我是非靜態方法中的代碼塊——被類對象調用時執行");
}
public static void staticFunction() {
System.out.println("我是靜態方法中的代碼塊——被類調用時執行");
}
}
測試類代碼如下:
/**
* Copyright (C), 2015-2020
* FileName: TestCodeBlock
* Author: niko
* Date: 2020/6/23 11:14
* Description:
* History:
* <author> <time> <version>
* 逝不等琴生 11:14 1.0
*/
package com.nzc.test;
import com.nzc.codeblock.CodeBlock;
public class TestCodeBlock {
public static void main(String[] args) {
new CodeBlock().normalFunction();
new CodeBlock().normalFunction();
System.out.println("=============以下爲靜態方法調用==========");
CodeBlock.staticFunction();
CodeBlock.staticFunction();
}
// 測試結果:
//我是靜態代碼塊——靜態代碼塊在類被加載的時候就運行了,而且只運行一次,並且優先於各種代碼塊以及構造函數
//我是構造代碼塊——優先於構造函數執行,每次創建一個對象都執行一次
//我是構造函數——每創建一個對象就執行一次
//我是非靜態方法中的代碼塊——被類對象調用時執行
//我是構造代碼塊——優先於構造函數執行,每次創建一個對象都執行一次
//我是構造函數——每創建一個對象就執行一次
//我是非靜態方法中的代碼塊——被類對象調用時執行
//=============以下爲靜態方法調用==========
//我是靜態方法中的代碼塊——被類調用時執行
//我是靜態方法中的代碼塊——被類調用時執行
}
測試結果如下圖所示:
總結:
即執行順序: 靜態代碼塊>構造代碼塊>構造函數>普通代碼塊
父類和子類中代碼塊執行順序
實例如下:
父類
public class Father {
static {
System.out.println("我是父類靜態代碼塊");
}
{
System.out.println("我是父類構造代碼塊");
}
public Father() {
System.out.println("我是父類構造函數");
}
}
子類
public class Son extends Father {
static {
System.out.println("我是子類靜態代碼塊");
}
{
System.out.println("我是子類構造代碼塊");
}
public Son() {
System.out.println("我是子類構造函數");
}
}
測試類如下
public class Test {
public static void main(String[] args) {
Son son1 = new Son();
System.out.println("===================");
Son son2 = new Son();
}
}
測試截圖:
總結:
靜態代碼塊內容先執行,隨後執行父類構造代碼塊和構造方法,接着執行子類構造代碼塊和構造方法。