1. 程式人生 > >深入理解JVM(八)——類載入的時機

深入理解JVM(八)——類載入的時機

這裡寫圖片描述

類的生命週期

一個類從載入進記憶體到卸載出記憶體為止,一共經歷7個階段:
載入——>驗證——>準備——>解析——>初始化——>使用——>解除安裝

其中,類載入包括5個階段:
載入——>驗證——>準備——>解析——>初始化

在類載入的過程中,以下3個過程稱為連線:
驗證——>準備——>解析

因此,JVM的類載入過程也可以概括為3個過程:
載入——>連線——>初始化

C/C++在執行前需要完成預處理、編譯、彙編、連結;而在Java中,類載入(載入、連線、初始化)是在程式執行期間完成的。
在程式執行期間進行類載入會稍微增加程式的開銷,但隨之會帶來更大的好處——提高程式的靈活性。Java語言的靈活性體現在它可以在執行期間動態擴充套件

,所謂動態擴充套件就是在執行期間動態載入動態連線

類載入的時機

1. 類載入過程中每個步驟的順序

我們已經知道,類載入的過程包括:載入、連線、初始化,連線又分為:驗證、準備、解析,所以說類載入一共分為5步:載入、驗證、準備、解析、初始化。

其中載入、驗證、準備、初始化的開始順序是依次進行的,這些步驟開始之後的過程可能會有重疊。
而解析過程會發生在初始化過程中。

2. 類載入過程中“初始化”開始的時機

JVM規範中只定義了類載入過程中初始化過程開始的時機,載入、連線過程都應該在初始化之前開始(解析除外),這些過程具體在何時開始,JVM規範並沒有定義,不同的虛擬機器可以根據具體的需求自定義。

初始化開始的時機:

  1. 在執行過程中遇到如下位元組碼指令時,如果類尚未初始化,那就要進行初始化:new、getstatic、putstatic、invokestatic。這四個指令對應的Java程式碼場景是:
    • 通過new建立物件;
    • 讀取、設定一個類的靜態成員變數(不包括final修飾的靜態變數);
    • 呼叫一個類的靜態成員函式。
  2. 使用java.lang.reflect進行反射呼叫的時候,如果類沒有初始化,那就需要初始化;
  3. 當初始化一個類的時候,若其父類尚未初始化,那就先要讓其父類初始化,然後再初始化本類;
  4. 當虛擬機器啟動時,虛擬機器會首先初始化帶有main方法的類,即主類;

3. 主動引用 與 被動引用

JVM規範中要求在程式執行過程中,“當且僅當”出現上述4個條件之一的情況才會初始化一個類。如果間接滿足上述初始化條件是不會初始化類的。
其中,直接滿足上述初始化條件的情況叫做主動引用;間接滿足上述初始化過程的情況叫做被動引用
那麼,只有當程式在執行過程中滿足主動引用的時候才會初始化一個類,若滿足被動引用就不會初始化一個類。

4. 被動引用的場景示例

  • 示例一
public class Fu{
    public static String name = "柴毛毛";
    static{
        System.out.println("父類被初始化!");
    }
}

public class Zi{
    static{
        System.out.println("子類被初始化!");
    }
}

public static void main(String[] args){
    System.out.println(Zi.name);
}

輸出結果:
父類被初始化!
柴毛毛
原因分析:
本示例看似滿足初始化時機的第一條:當要獲取某一個類的靜態成員變數的時候如果該類尚未初始化,則對該類進行初始化。
但由於這個靜態成員變數屬於Fu類,Zi類只是間接呼叫Fu類中的靜態成員變數,因此Zi類呼叫name屬性屬於間接引用,而Fu類呼叫name屬性屬於直接引用,由於JVM只初始化直接引用的類,因此只有Fu類被初始化。

  • 示例二
public class A{
    public static void main(String[] args){
        Fu[] arr = new Fu[10];
    }
}

輸出結果:
並沒有輸出“父類被初始化!”
原因分析:
這個過程看似滿足初始化時機的第一條:遇到new建立物件時若類沒被初始化,則初始化該類。
但現在通過new要建立的是一個數組物件,而非Fu類物件,因此也屬於間接引用,不會初始化Fu類。

  • 示例三
public class Fu{
    public static final String name = "柴毛毛";
    static{
        System.out.println("父類被初始化!");
    }
}

public class A{
    public static void main(String[] args){
        System.out.println(Fu.name);
    }
}

輸出結果:
柴毛毛
原因分析:
本示例看似滿足類初始化時機的第一個條件:獲取一個類靜態成員變數的時候若類尚未初始化則初始化類。
但是,Fu類的靜態成員變數被final修飾,它已經是一個常量。被final修飾的常量在Java程式碼編譯的過程中就會被放入它被引用的class檔案的常量池中(這裡是A的常量池)。所以程式在執行期間如果需要呼叫這個常量,直接去當前類的常量池中取,而不需要初始化這個類。

5. 介面的初始化

介面和類都需要初始化,介面和類的初始化過程基本一樣,不同點在於:類初始化時,如果發現父類尚未被初始化,則先要初始化父類,然後再初始化自己;但介面初始化時,並不要求父介面已經全部初始化,只有程式在執行過程中用到當父介面中的東西時才初始化父介面。

這裡寫圖片描述

相關推薦

深入理解JVM()——載入時機

類的生命週期 一個類從載入進記憶體到卸載出記憶體為止,一共經歷7個階段: 載入——>驗證——>準備——>解析——>初始化——>使用——>解除安裝 其中,類載入包括5個階段: 載入——>驗證——>準備——

深入理解jvm載入機制

一、類的生命週期 java程式使用某個類時,必須按照以下順序執行: (1)載入:查詢並載入類的二進位制資料; (2)連線:包括驗證、準備和解析類的二進位制; 驗證:確保載入類的正確性;準備:為類的靜態變數分配記憶體,並將其初始化為預設值;解析:把類中的符號引用轉為直接引用(3)初始化:給類的靜態變數賦

深入理解JVM(六)檔案結構

6.1 關於類檔案   1.class檔案的一次編譯,到處執行的跨平臺性;    2.JVM不止有跨平臺性,還有跨語言性,不管是JRuby還是Groovy寫出來的程式,只要編譯出符合JVM規範的class檔案就可以在JVM上執行; 6.2 類檔案結構   PS:任何一個Class檔案都對應一個類或者介

深入理解Java:載入機制及反射

 說明:本文乃學習整理參考而來. 一、Java類載入機制 1.概述        Class檔案由類裝載器裝載後,在JVM中將形成一份描述Class結構的元資訊物件,通過該元資訊物件可以獲知Class的結構資訊:如建構函式,屬性和方法等,Java允許使用者藉由這個Class相關的元資訊物件間接呼

深入理解JVM(③)虛擬機器的載入時機

## 前言 Java虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別,這個過程被稱為虛擬機器的類載入機制。 ### 類載入的時機 一個型別從被載入到虛擬機器記憶體中開始,到解除安裝除記憶體為止,它的生命週期將會經歷==載入(L

深入理解JVM虛擬機器讀書筆記【第九章】載入及執行子系統的案例與實戰

9.1 概述 9.2 案例分析 9.2.1 Tomcat:正統的類載入器架構 9.2.2 OSGI:靈活的類載入器架構 9.2.3 位元組碼生成技術與動態代理

深入理解JVM虛擬機器讀書筆記【第七章】虛擬機器載入機制

7.1 概述 7.2 類載入的時機 7.3 類載入的過程 7.3.1 載入 7.3.2 驗證 1.檔案格式驗證 2.元資料驗證 3.位元組碼驗證

深入理解JVM(七)——虛擬機器載入機制

虛擬機器類載入機制 虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗,轉換解析,初始化,最終形成可以被虛擬機器直接使用的Java型別,這就是Java的類載入機制。 類的載入,連線,初始化是在程式執行時完成的。 生命週期 載入—->連線(驗證->

深入理解JVM讀書筆記二:虛擬機器載入機制

一、概述      虛擬機器把描述類的資料從class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化。最終形成可以被虛擬機器最直接使用的java型別的過程就是虛擬機器的類載入機制。      與那些在編譯時需要進行連線工作的語

深入理解JVM(六):虛擬機器載入機制

虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別,這就是虛擬機器的類載入機制。 在Java中,型別的載入、連線和初始化過程都是程式在執行期間完成的,這種策略雖然會令類載入時稍微增

深入理解JVM(六)——載入器原理

我們知道我們編寫的java程式碼,會經過編譯器編譯成位元組碼檔案(class檔案),再把位元組碼檔案裝載到JVM中,對映到各個記憶體區域中,我們的程式就可以在記憶體中運行了。那麼位元組碼檔案是怎樣裝載到JVM中的呢?中間經過了哪些步驟?常說的雙親委派模式又是怎麼回事?本文主要搞清楚這些問題。 類

深入理解JVM載入機制

深入理解JVM類載入機制 轉載自:https://blog.csdn.net/a724888/article/details/78396462 簡述:虛擬機器把描述類的資料從class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別,這就是虛

深入理解JVM】:載入機制

概述 虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別,這就是虛擬機器的類載入機制。 與那些在編譯時需要進行連結工作的語言不同,在Java語言裡,型別的載入、連線和初始化過程

深入理解JVM(七)JVM載入機制

7.1JVM類載入機制   虛擬機器把資料從Class檔案載入到記憶體,並且校驗、轉換解析和初始化最終形成可以被虛擬機器使用的Java型別,這就是虛擬機器的類載入機制。 7.2類載入的時機   1.類載入的步驟開始的順序: 載入(Loading) -> 驗證(Veri

深入理解JVM(③)虛擬機器的載入過程

## 前言 上一篇我們介紹到一個類的生命週期大概分7個階段:載入、驗證、準備、解析、初始化、使用、解除安裝。並且也介紹了類的載入時機,下面我們將介紹一下虛擬機器中類的載入的全過程。**主要是類生命週期的,載入、驗證、準備、解析和初始化這五個階段所執行的具體動作。** ### 載入 類載入過程的第一個階段就是載

深入理解JVM(六)——加載器原理

區域 (六) HR tcl parse cep 引用關系 throws wid 我們知道我們編寫的java代碼,會經過編譯器編譯成字節碼文件(class文件),再把字節碼文件裝載到JVM中,映射到各個內存區域中,我們的程序就可以在內存中運行了。那麽字節碼文件是怎樣裝載到JV

JVM虛擬機深入理解+GC回收+加載

bae base class class對象 對象復制 可用內存 虛擬機棧 程序設計 訪問 旭日Follow_24 的CSDN 博客 ,全文地址請點擊: https://blog.csdn.net/xuri24/article/details/81455449 一,前言

深入理解JVM虛擬機器讀書筆記【第章】虛擬機器位元組碼執行引擎

8.1 概述 8.2 執行時棧幀結構 8.2.1 區域性變量表 8.2.2 運算元棧 8.2.3 動態連線 8.2.4 方法返回地址

深入理解JVM)——位元組碼執行引擎

不用虛擬機器,執行引擎在執行Java程式碼時,會有解釋執行(通過直譯器執行)和編譯執行(通過及時編譯器產生原生代碼執行)兩種選擇。 執行時棧幀結構 棧幀用於支援虛擬機器進行方法呼叫和方法執行的資料結構。棧幀儲存了方法的區域性變量表,運算元棧,動態連線和方法返回地址等資訊。每一個方法從

深入理解JVM(六)——檔案結構——code

Code Java程式中方法體中的程式碼經過Javac編譯器處理之後,最終變成位元組碼指令儲存在Code屬性內。 Code屬性出現在方法表的屬性集合之中,但不是所有的方法表都必須有,譬如介面或者抽象類。 Code是Class檔案中最重要的一個屬性,如果把一個Java程式中的資訊分