深入java虛擬機之類加載機制,可以在java虛擬機中運行

本文目錄一覽:

java 類加載機制有什麼用

AVA類加載機制詳解

“代碼編譯的結果從本地機器碼轉變為字節碼,是存儲格式發展的一小步,卻是變成語言發展的一大步”,這句話出自《深入理解JAVA虛擬機》一書,後面關於jvm的系列文章主要都是參考這本書。

JAVA源碼編譯由三個過程組成:

1、源碼編譯機制。

2、類加載機制

3、類執行機制

我們這裡主要介紹編譯和類加載這兩種機制。

一、源碼編譯

代碼編譯由JAVA源碼編譯器來完成。主要是將源碼編譯成字節碼文件(class文件)。字節碼文件格式主要分為兩部分:常量池和方法字節碼。

二、類加載

類的生命周期是從被加載到虛擬機內存中開始,到卸載出內存結束。過程共有七個階段,其中到初始化之前的都是屬於類加載的部分

加載—-驗證—-準備—-解析—–初始化—-使用—–卸載

系統可能在第一次使用某個類時加載該類,也可能採用預加載機制來加載某個類,當運行某個java程序時,會啟動一個java虛擬機進程,兩次運行的java程序處於兩個不同的JVM進程中,兩個jvm之間並不會共享數據。

1、加載階段

這個流程中的加載是類加載機制中的一個階段,這兩個概念不要混淆,這個階段需要完成的事情有:

1)通過一個類的全限定名來獲取定義此類的二進制字節流。

2)將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。

3)在java堆中生成一個代表這個類的Class對象,作為訪問方法區中這些數據的入口。

由於第一點沒有指明從哪裡獲取以及怎樣獲取類的二進制字節流,所以這一塊區域留給我開發者很大的發揮空間。這個我在後面的類加載器中在進行介紹。

2、準備階段

這個階段正式為類變量(被static修飾的變量)分配內存並設置類變量初始值,這個內存分配是發生在方法區中。

1、注意這裡並沒有對實例變量進行內存分配,實例變量將會在對象實例化時隨着對象一起分配在JAVA堆中。

2、這裡設置的初始值,通常是指數據類型的零值。

private static int a = 3;

這個類變量a在準備階段後的值是0,將3賦值給變量a是發生在初始化階段。

3、初始化階段

初始化是類加載機制的最後一步,這個時候才正真開始執行類中定義的JAVA程序代碼。在前面準備階段,類變量已經賦過一次系統要求的初始值,在初始化階段最重要的事情就是對類變量進行初始化,關注的重點是父子類之間各類資源初始化的順序。

java類中對類變量指定初始值有兩種方式:1、聲明類變量時指定初始值;2、使用靜態初始化塊為類變量指定初始值。

初始化的時機

1)創建類實例的時候,分別有:1、使用new關鍵字創建實例;2、通過反射創建實例;3、通過反序列化方式創建實例。

new Test();

Class.forName(“com.mengdd.Test”);

2)調用某個類的類方法(靜態方法)

Test.doSomething();

3)訪問某個類或接口的類變量,或為該類變量賦值。

int b=Test.a;

Test.a=b;

4)初始化某個類的子類。當初始化子類的時候,該子類的所有父類都會被初始化。

5)直接使用java.exe命令來運行某個主類。

除了上面幾種方式會自動初始化一個類,其他訪問類的方式都稱不會觸發類的初始化,稱為被動引用。

1、子類引用父類的靜態變量,不會導致子類初始化。

public class SupClass

{    public static int a = 123;

static

{

System.out.println(“supclass init”);

}

}public class SubClass extends SupClass

{    static

{

System.out.println(“subclass init”);

}

}public class Test

{    public static void main(String[] args)

{

System.out.println(SubClass.a);

}

}

執行結果:

supclass init123

2、通過數組定義引用類,不會觸發此類的初始化

public class SupClass

{    public static int a = 123;

static

{

System.out.println(“supclass init”);

}

}public class Test

{    public static void main(String[] args)

{

SupClass[] spc = new SupClass[10];

}

}

執行結果:

3、引用常量時,不會觸發該類的初始化

public class ConstClass

{    public static final String A=  “MIGU”;

static

{

System.out.println(“ConstCLass init”);

}

}public class TestMain

{    public static void main(String[] args)

{

System.out.println(ConstClass.A);

}

}

執行結果:

MIGU

用final修飾某個類變量時,它的值在編譯時就已經確定好放入常量池了,所以在訪問該類變量時,等於直接從常量池中獲取,並沒有初始化該類。

初始化的步驟

1、如果該類還沒有加載和連接,則程序先加載該類並連接。

2、如果該類的直接父類沒有加載,則先初始化其直接父類。

3、如果類中有初始化語句,則系統依次執行這些初始化語句。

在第二個步驟中,如果直接父類又有直接父類,則系統會再次重複這三個步驟來初始化這個父類,依次類推,JVM最先初始化的總是java.lang.Object類。當程序主動使用任何一個類時,系統會保證該類以及所有的父類都會被初始化。

JVM之class加載過程

java虛擬機把描述類的數據從class文件加載到內存,並對數據進行 校驗/準備/解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這個過程被稱作虛擬機的類加載機制。

稱作虛擬機的類加載機制。

loading – linking (verification – preparation – resolution)- resolution)-initializing

loading: 把class文件load到內存中,採用雙親委派,主要是為了安全性

verification: 校驗class文件是否符合標準

preparation: 靜態變量分配內存並設初始值的階段(不包括實例變量)

resolution:把符號引用轉換為直接引用

initializing:靜態變量賦初始值

類加載的過程主要分為三個部分:加載、連接、初始化這三個階段。

類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個這個類的java.lang.Class對象,用來封裝類在方法區類的對象。主要步驟可以分為下面的三件事情:

加載階段完成後,虛擬機外部的 二進制字節流就按照虛擬機所需的格式存儲在方法區之中,而且在Java堆中也創建一個java.lang.Class類的對象,這樣便可以通過該對象訪問方法區中的這些數據。

類的加載的最終產品是位於堆區中的Class對象。Class對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的接口。加載類的方式有以下幾種:

2.加載器

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

1.BootstrapClassLoader(啟動類加載器)

在連接裡面又可以被分成3個小階段,分別是:驗證,準備,解析

1.驗證(目的):

2.驗證內容:

驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。驗證階段大致會完成4個階段的檢驗動作:

驗證階段是非常重要的,但不是必須的,它對程序運行期沒有影響,如果所引用的類經過反覆驗證,那麼可以考慮採用-Xverifynone參數來關閉大部分的類驗證措施,以縮短虛擬機類加載的時間。

3.準備:

在準備階段,為靜態變量的初值為jvm默認的初值,而不是我們在程序中設定的初值。jvm默認為靜態變量的初值是這樣的

4.解析:

這一階段的任務就是把常量池中的符號引用轉換為直接引用 什麼是符號引用,什麼是直接引用。

1.工作內容:

JVM負責主要對類變量(類變量就是static修改的變量)進行初始化這裡主要對類變量(類變量就是static修改的變量)進行初始化,初始化主要有兩個方式:

2.初始化時機:

類初始化時機:只有當對類的主動使用的時候才會導致類的初始化,類的主動使用包括以下六種:

3.初始化順序:

如果有父類,則順序是:父類static方法/static變量賦值 – 子類static方法/static變量賦值

三、結語:

上面介紹的就是類(class)的加載,包含它的加載、鏈接、初始化。

Android進階知識點,我最近整理了許多,裡面講解的非常詳細。取

技術進階手冊丶面試題綱丶核心筆記資料。

描述一下JVM加載class文件的原理?

Java語言是一種具有動態性的解釋型語言,類(class)只有被加載到JVM中後才能運行。當運行指定程序時,JVM會將編譯生成的.class文件按照需求和一定的規則加載到內存中,並組織成為一個完整的Java應用程序。這個加載過程是由類加載器來完成的,具體來說,就是由ClassLoader和它的子類來實現的。類加載器本身也是一個類,其實質是把類文件從硬盤讀取到內存中。

類的加載方式分為隱式加載與顯式加載兩種。隱式加載指的是程序在使用new等方法創建對象時,會隱式地調用類的加載器把對應的類加載到JVM中。顯式加載指的是通過直接調用class.forName()方法來把所需要的類加載到JVM中。

任何一個工程項目都是由許多個類組成的,當程序啟動時,只把需要加載的類加載到JVM中,其他類只有被使用到的時候才會被加載,採用這種方法,一方面可以加快加載速度,另外一方面可以節約程序運行過程中對內存的開銷。此外,在Java語言中,每個類或接口都對應一個.class文件,這些文件可以被看成一個個可以被動態加載的單元,因此當只有部分類被修改時,只需要重新編譯變化的類即可,而不需要重新編譯所有文件,因此加快了編譯速度。

java虛擬機字節碼執行和類加載機制有什麼關係

沒什麼關係

編譯成.class是為了在不同平台的虛擬機上都能運行

類的加載機制則是語言特性方面的東西

這倆不是一個體系的概念,不應該放在一起討論

深入java虛擬機,絕版和深入理解Java虛擬機:JVM高級特性與最佳實踐。

市面上關於jvm的書少之又少,要不是周志明出的這本深入理解java虛擬機,那麼中文jvm的書籍可以說是有10年的空隙了,上一版還是02年的《java虛擬機規範》了。\x0d\x0a從時效上來說,《深入java虛擬機》出自2000年,技術上已然是滯後很多了。\x0d\x0a所以這兩者比較,絕對推薦後者。\x0d\x0a\x0d\x0a另外單《深入理解java虛擬機》一書來評價,絕對算是一本好書了,掌握此書內容後,基本可以解決java程序員日常遇到的虛擬機先關問題(OOM,調優,GC等),以及應付各種關於該條目的面試筆試問題。\x0d\x0a其中,java內存管理,類加載機制,垃圾回收建議重點閱讀\x0d\x0a\x0d\x0a國外的了解不多,但是就目前來看,建議樓主先吃透周志明老師的這本。有基礎還想深入的話,java虛擬機規範這種官方標準文檔放着呢。

原創文章,作者:TMXT,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/149883.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
TMXT的頭像TMXT
上一篇 2024-11-05 16:55
下一篇 2024-11-05 16:55

相關推薦

  • Java Bean加載過程

    Java Bean加載過程涉及到類加載器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean加載的過程。 一、類加載器 類加載器是Java虛擬機…

    編程 2025-04-29
  • QML 動態加載實踐

    探討 QML 框架下動態加載實現的方法和技巧。 一、實現動態加載的方法 QML 支持從 JavaScript 中動態指定需要加載的 QML 組件,並放置到運行時指定的位置。這種技術…

    編程 2025-04-29
  • 類加載的過程中,準備的工作

    類加載是Java中非常重要和複雜的一個過程。在類加載的過程中,準備階段是其中一個非常重要的步驟。準備階段是在類加載的連接階段中的一個子階段,它的主要任務是為類的靜態變量分配內存,並…

    編程 2025-04-28
  • Lazarus LoadLibrary:DLL動態鏈接庫的加載和使用

    本文將從以下幾個方面介紹Lazarus中LoadLibrary和FreeLibrary函數的使用方法: 一、簡介 LoadLibrary和FreeLibrary是Windows動態…

    編程 2025-04-27
  • Spring Boot本地類和Jar包類加載順序深度剖析

    本文將從多個方面對Spring Boot本地類和Jar包類加載順序做詳細的闡述,並給出相應的代碼示例。 一、類加載機制概述 在介紹Spring Boot本地類和Jar包類加載順序之…

    編程 2025-04-27
  • 用Python加載鳶尾花數據

    本文將詳細介紹如何使用Python加載鳶尾花數據,包括數據源的介紹、數據的獲取和清洗、數據可視化等方面。 一、數據源的介紹 鳶尾花數據集(Iris dataset)是常用的分類實驗…

    編程 2025-04-27
  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • 深入理解byte轉int

    一、字節與比特 在討論byte轉int之前,我們需要了解字節和比特的概念。字節是計算機存儲單位的一種,通常表示8個比特(bit),即1字節=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25

發表回復

登錄後才能評論