1. 程式人生 > >理解Java中的靜態域、程式碼塊和記憶體區域圖

理解Java中的靜態域、程式碼塊和記憶體區域圖

Java面向物件(二) 靜態域、程式碼塊和記憶體區域圖

靜態域

  • 將域定義成static後,每個只有一個這樣的域,與類相關的,也稱為類成員。但是每個物件對於所有的例項域都有自己的一份拷貝
  • 靜態域隨著類的載入而載入並初始化,存在於方法區記憶體中位元組碼檔案的靜態區域中。
  • 優先於物件存在,先有方法區的類載入,後才可能會有堆記憶體的物件例項化。
  • 靜態域會被所有的物件共享,也稱為共享區。
  • 一般共性用靜態,特性用非靜態。
  • 一般通過類名直接呼叫,雖然也可以通過物件名呼叫,但是不推薦,也不合適。

static關鍵字注意事項

  • 在靜態方法中沒有this關鍵字
    • 靜態是隨著類的載入而初始化,而this
      隨著物件的建立而存在的。
    • 靜態比物件優先存在。
  • 靜態方法只能訪問靜態成員和靜態成員方法,即靜態只能訪問靜態
    • 靜態方法:
      • 成員變數:只能訪問靜態變數
      • 成員方法:只能訪問靜態成員方法
    • 非靜態方法:
      • 成員變數:可以是靜態的,也可以是非靜態的
      • 成員方法:可以是靜態的成員方法,也可以是非靜態的成員方法。

靜態變數和成員變數區別

  • 靜態變數也叫類變數,成員變數也叫物件變數。
  • 所屬不同
    • 靜態變數屬於
    • 成員變數屬於物件
  • 記憶體中的位置不同:
    • 靜態變數儲存於方法區的靜態區
    • 成員變數儲存於堆記憶體

程式碼塊

程式碼塊概述

  • Java中,使用{}括起來的程式碼稱為程式碼塊

程式碼塊的分類

  • 根據位置和宣告的不同,可以分為區域性程式碼塊,構造程式碼塊,靜態程式碼塊和同步程式碼塊

程式碼塊的應用

  • 區域性程式碼塊
    • 方法中出現,可以限定變數的生命週期,及早釋放,提高記憶體利用率
  • 構造程式碼塊(初始化程式碼塊)
    • 在類中方法外出現,將多個構造器中的相同程式碼放到一起,每次呼叫構造器都執行,並且在構造方法前執行
  • 靜態程式碼塊
    • 在類中方法外出現,並且用static修飾,用於給程式碼塊中的程式碼靜態化,加入靜態域中,在類載入的時候直接執行,並且只執行一次。
    • 靜態程式碼塊優先於main方法執行。
    • 一般常用於載入驅動IO操作等消耗資源的程式碼

程式碼塊面試題

根據程式寫輸出結果,考察執行順序

class Student {
		static {
			System.out.println("Student 靜態程式碼塊");
		}
		
		{
			System.out.println("Student 構造程式碼塊");
		}
		
		public Student() {
			System.out.println("Student 構造方法");
		}
}
	
class StudentTest {
    static {
        System.out.println("StudentTest靜態程式碼塊");
    }

    public static void main(String[] args) {
        System.out.println("我是main方法");

        Student s1 = new Student();
        Student s2 = new Student();
    }
}

測試結果:

StudentTest靜態程式碼塊
我是main方法
Student 靜態程式碼塊
Student 構造程式碼塊
Student 構造方法
Student 構造程式碼塊
Student 構造方法

分析:

​ main方法是Java程式的入口,JVM先找main方法,先把有main方法的類載入到記憶體中,此時StudentTest類的靜態程式碼塊直接隨著類的載入而先執行;

​ 隨後main方法開始執行,當Student類被例項化後,Student類的靜態程式碼塊先執行,並且只執行一個,不管例項化多少物件;

​ 之後,每例項化一次Student類,類中的構造程式碼塊比構造方法就會先執行,並且每例項化一次就執行一次。

初始化執行順序總結

  • 當程式執行時,如果需要建立某個類的物件,那麼Java會先檢查是否載入了這個類,如果沒有載入,則先執行類的載入再生成物件。如果已經載入,則直接生成物件。
  • 類的執行順序過程:
    • 首先類先載入到方法區記憶體中,類的靜態域會先被載入並且初始化並且優先於main方法執行。Java中類的載入時按需載入,需要時才載入,並且只加載一次。
      • 靜態成員變數和靜態程式碼塊的執行順序同程式碼中的順序一致。
    • 每建立一次物件時,先初始化物件中的成員變數,再執行構造程式碼塊,其次再執行構造方法。
      • 類中的變數會在任何方法(包括構造器)呼叫之前得到初始化,即使變數散佈於方法定義之間。

Java記憶體區域分配

  • 此分配圖基於Java8之前版本

 Java記憶體區域分配