最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java類加載之Class對象到Klass模型詳解

 更新時間:2023年08月30日 10:07:34   作者:云下牧羊人  
這篇文章主要介紹了Java類加載之Class對象到Klass模型詳解,每一個Java類在JVM中都會對應創(chuàng)建一個C++類實例,我們稱這個C++類為Klass實例,Klass實例里面存儲了java類中所描述的方法、字段、屬性等,需要的朋友可以參考下

前言

JVM只認識Class文件,也就是說,任何一門計算機語言,只要它最后將代碼編譯成class文件,都能被JVM所執(zhí)行。

Kotlin、Groovy、JRuby、Jython、Scala等語言就是如此。

一、什么是Class文件

1. class文件是Java代碼經(jīng)過Javac編譯后生成的字節(jié)碼文件,如下圖所示。

圖1

2. class文件主要包含了魔數(shù)、JVM版本號、常量池、常量池計數(shù)器、訪問標識等信息,如下圖所示(截取自 Java虛擬機規(guī)范)

在這里插入圖片描述

  • magic:魔數(shù),占4字節(jié)。作用是判斷這個文件是否為一個虛擬機所能接受的class文件
  • minor_version::副版本號,占2字節(jié),最小支持版本號。
  • major_version:主版本號,占2字節(jié),最大支持版本號。
  • constant_pool_count:常量池計數(shù)器,記錄常量池表中的成員數(shù),它的值為常量池表中的成員數(shù)+1,常量池表的索引值只有在大于0并且小于constant_pool_count時才認為是有效。
  • constant_pool:常量池,包含class文件結(jié)構(gòu)及其子結(jié)構(gòu)中所引用的所有字符串常量、類或接口、字段名和其他常量。
  • access_flag:訪問標志,用于表示類或接口的訪問權(quán)限及屬性。
  • this_class:類索引。
  • super_class:父類索引。
  • interfaces_count:接口計數(shù)器。
  • interfaces_count[]:接口表。
  • fields_count:字段計數(shù)器。
  • fields:字段表。
  • methods_count:方法計數(shù)器。
  • methods[]:方法表。
  • attributes_count:屬性計數(shù)器。
  • attributes[]:屬性表。

3. 每一個Java類在JVM中都會對應創(chuàng)建一個C++類實例,我們稱這個C++類為Klass實例(對應hotspot源碼中的instanceKlass類)。

Klass實例里面存儲了java類中所描述的方法、字段、屬性等。

如下圖所示,instanceKlass的字段皆為存儲java類文件中的數(shù)據(jù)所設計,詳見hotspot源碼中 instanceKlass.hpp文件。

在這里插入圖片描述

ps:JVM在創(chuàng)建InstanceKlass對象時,為其申請的內(nèi)存空間,遠超instanceKlass本身所需要得空間,這是因為InstanceKlass還要存虛表、接口表、以及Java類中的引用類型表。

二、class類加載的過程

你每寫的一個Java類,在JVM中,都有一個對應的C++類實例,這個C++類實例,我們管它叫Klass類,它存儲了類的元信息(常量池、屬性、方法等)。

1. 加載階段

  • 通過類的全限定名獲取java類編譯后生成的class文件,加載進JVM,并解析class文件。
  • 解析完成后,JVM便會在內(nèi)部創(chuàng)建一個與Java類對等的類模板對象 instanceKlass實例(也是C++的一個類,里面保存了java類的常量池、方法、屬性等信息)。

下面奉上hotspot源碼解析常量池、字段、方法并創(chuàng)建對應的Klass對象部分,代碼皆在ClassFileParser.cpp的 parseClassFile方法中,有興趣的同學可以自己看一看。

以下僅截取部分主要代碼

instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
                                                    ClassLoaderData* loader_data,
                                                    Handle protection_domain,
                                                    KlassHandle host_klass,
                                                    GrowableArray<Handle>* cp_patches,
                                                    TempNewSymbol& parsed_name,
                                                    bool verify,
                                                    TRAPS) {
  // Constant pool   解析常量池
  constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
 //......
    //解析Java類字段
    Array<u2>* fields = parse_fields(class_name,
                                     access_flags.is_interface(),
                                     &fac, &java_fields_count,
                                     CHECK_(nullHandle));
    //......
    //解析Java類方法
    Array<Method*>* methods = parse_methods(access_flags.is_interface(),
                                            &promoted_flags,
                                            &has_final_method,
                                            &declares_default_methods,
                                            CHECK_(nullHandle));
    //....
    // 開始創(chuàng)建與Java對等的Klass對象
    _klass = InstanceKlass::allocate_instance_klass(loader_data,
                                                    vtable_size,
                                                    itable_size,
                                                    info.static_field_size,
                                                    total_oop_map_size2,
                                                    rt,
                                                    access_flags,
                                                    name,
                                                    super_klass(),
                                                    !host_klass.is_null(),
                                                    CHECK_(nullHandle));
}

4.通過instanceKlass生成一個鏡像類,放在堆區(qū),即instanceMirrorKlass實例(對應hotspot源碼中的 instanceMirrorKlass類)。

instanceKlass供jvm內(nèi)部使用,小編認為多生成一個instanceMirrorKlass是因為考慮到運行安全因素,不能直接把類暴露給外部使用,所以弄出了個鏡像類實例提供給外部程序調(diào)用。

小貼紙:

1.java類中的靜態(tài)變量會存儲在instanceMirrorKlass類中,instanceMirrorKlass類里面比instanceKlass類多定義了一個靜態(tài)字段偏移量的屬性,可以通過該屬性獲取靜態(tài)變量。

在這里插入圖片描述

2.Java中的數(shù)組類在運行時數(shù)據(jù)區(qū)的生成的實例為

方法區(qū):ArrayKlass。堆區(qū):基本類型數(shù)組 TypeArrayKlass,引用類型數(shù)組ObjArrayKlass 分別對應hotspot源碼里的TypeArrayKlass.cpp 與 ObjArrayKlass.cpp類

3.類加載器是什么時候加載的,如下圖,hotspot源碼java.c中有一個javaMain方法,javaMain 里面調(diào)用了LoadMainClass 方法,你的一切疑惑都在LoadMainClass里面,它的執(zhí)行邏輯是通過啟動類加載器加載類sun.launcher.LauncherHelper,執(zhí)行該類的方法checkAndLoadMain,加載main函數(shù)所在的類,啟動擴展類加載器、應用類加載器也是在這個時候完成的。

在這里插入圖片描述

2. 驗證

驗證主要就是對Java虛擬機定義的一些約束進行校驗,如果校驗不通過就拋出異常。

  • 靜態(tài)約束:
  • 結(jié)構(gòu)化約束

3. 準備

創(chuàng)建類或接口的靜態(tài)字段,并用默認值初始化這些字段。這個階段不會執(zhí)行任何的虛擬機字節(jié)碼指令。

數(shù)據(jù)類型默認值
byte(byte)0
shot(shot)0
long0L
char‘\u0000’
int0
float0.0f
double0.0d
boolean0(false)

final修飾類的變量,已經(jīng)不會再 發(fā)生變化,所以在準備階段就進行賦值了,就沒有賦初值這個操作了。

4. 解析

我們從各種某度的文章里總會看到,解析的主要過程就是將符號引用替換為直接引用。

那么什么是符號引用呢? 如下圖,下圖采用了jclasslib插件展示一個Java類文件編譯后產(chǎn)生的class文件信息。

我們可以看到方法里面字節(jié)碼指令后面的 #1等符號就是我們常說的符號引用。

在這里插入圖片描述

這個符號引用其實就是常量池中的索引(例如#1指向的就是常量池中的第一個類或方法) 如下圖所示

在這里插入圖片描述

JVM會在準備階段將這些索引符號替換為直接內(nèi)存地址。以供后續(xù)JVM指令進行調(diào)用。

都有那些虛擬機指令需要進行符號引用的解析呢?

anewarray、checkcast、getfield、getstatic、instanceof、nvokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、multianewarray、new、putfield、putstatic

執(zhí)行上述任何一條指令都需要對它的符號引用進行解析。

如果在某個符號引用解析過程中發(fā)生錯誤,那么應該在使用該符號引用的程序處拋出IncompatibleClassChangeError或者其子類的異常

5. 初始化

初始化就是 執(zhí)行類的靜態(tài)代碼塊,并且完成靜態(tài)變量的賦值,我們可以看到

如下圖,如果我們的代碼里要是有靜態(tài)變量,并且對靜態(tài)變量進行賦值了,那么生成的字節(jié)碼文件中就會有clinit方法。

這個clinit就是執(zhí)行靜態(tài)變量賦值的指令,而且方法中語句的先后順序與代碼的編寫順序相關

在這里插入圖片描述

既然初始化的時候可以直接對變量進行賦值,那我們是否可以跳過準備階段,直接在初始化階段進行賦值

。因為準備階段主要是賦初值,那我們可以直接要我們寫的值,不要初始值。 答案當然是不行,原因如下

初始化階段主要是依靠clinit方法生成的指令進行賦值,但是如果我們定義一個空的靜態(tài)變量,那clinit方法中就不會生成這個靜態(tài)變量相關的賦值代碼。

如下圖,所以這時就需要準備階段給這個靜態(tài)變量初始化、賦初值,否則這個變量就丟掉了。

在這里插入圖片描述

初始化之后就由JVM的執(zhí)行引擎進行取指執(zhí)行了,執(zhí)行引擎有些過于復雜,以后有機會再分析吧。

總結(jié)

  1. JVM能執(zhí)行的就是Class文件,所有計算機語言只要最后生成了Class文件,都可以交給JVM執(zhí)行。Kotlin、Groovy、JRuby、Jython、Scala等語言就是如此。
  2. 由于JVM是由C/C++編寫的,所以每一個Java類加載到JVM時都會生成一個對應的C++類,即instanceKlass,存放在方法區(qū)(元空間)。同時生成一個instanceKlass的實例對象,即instanceMirrorKlass,放在堆區(qū)。
  3. JVM類加載機制分為,加載、驗證、準備、解析、初始化五個階段。
  4. 加載階段:
    通過類的全限定名獲取存儲該類的class文件,并對其進行解析
    解析后生成對應的C++模板類,即instanceKlass實例,存放在元空間,用于JVM內(nèi)部使用
    在堆區(qū)生成該類的Class對象實例,即instanceMirrorKlass,用于其他系統(tǒng)或程序進行調(diào)用。
  5. 驗證階段主要有靜態(tài)約束校驗,結(jié)構(gòu)化約束校驗兩種。
  6. 準備階段主要是對靜態(tài)變量賦初值的操作
  7. 解析階段就是將符號引用(常量池索引)替換為直接引用(方法內(nèi)存地址)
  8. 初始化就是 執(zhí)行類的靜態(tài)代碼塊,并且完成靜態(tài)變量的賦值。賦值的指令會生成在clinit方法中,當在Java代碼中對靜態(tài)變量賦值了,clinit中才會生成對應的指令。

擴展問題

  • 類的初始化階段會不會有線程安全問題?
  • 類加載階段會使用synchronized鎖機制嗎?
  • 類加載時延遲偏向鎖的原因?
  • 如果實現(xiàn)一個類加載器,不按照類加載器機制實現(xiàn)可不可以?

到此這篇關于Java類加載之Class對象到Klass模型詳解的文章就介紹到這了,更多相關Java的Class對象到Klass模型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 解讀yml文件中配置時間類型的轉(zhuǎn)換方式

    解讀yml文件中配置時間類型的轉(zhuǎn)換方式

    這篇文章主要介紹了yml文件中配置時間類型的轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java中的SynchronousQueue隊列詳解

    Java中的SynchronousQueue隊列詳解

    這篇文章主要介紹了Java中的SynchronousQueue隊列詳解,SynchronousQueue是BlockingQueue的一種,所以SynchronousQueue是線程安全的,SynchronousQueue和其他的BlockingQueue不同的是SynchronousQueue的capacity是0,需要的朋友可以參考下
    2023-12-12
  • 深入解析Maven 插件參數(shù)注入與Mojo開發(fā)

    深入解析Maven 插件參數(shù)注入與Mojo開發(fā)

    本文將深入探討Mojo開發(fā)中的參數(shù)處理機制,通過剖析@Parameter注解的實現(xiàn)原理、對比字段注入與Setter方法注入的底層差異,并結(jié)合Apache Maven 3.9.x版本的源碼解析,為讀者構(gòu)建完整的插件開發(fā)知識體系,感興趣的朋友一起跟隨小編學校吧
    2025-05-05
  • SpringBoot FailureAnalyzer實例使用教程

    SpringBoot FailureAnalyzer實例使用教程

    FailureAnalyzer是一種在啟動時攔截exception并將其轉(zhuǎn)換為human-readable消息的好方法,包含在故障分析中。SpringBoot為application context相關的exceptions,JSR-303驗證等提供了這樣的分析器,實際上很容易創(chuàng)建自己的
    2022-12-12
  • Java報錯:ClassCastException問題解決方法

    Java報錯:ClassCastException問題解決方法

    異常是程序中的一些錯誤,但并不是所有的錯誤都是異常,并且錯誤有時候是可以避免的,下面這篇文章主要給大家介紹了關于Java報錯:ClassCastException問題解決方法,需要的朋友可以參考下
    2024-07-07
  • Java中字符串String的+和+=及循環(huán)操作String原理詳解

    Java中字符串String的+和+=及循環(huán)操作String原理詳解

    Java編譯器在編譯時對String的+和+=操作會創(chuàng)建StringBuilder對象來進行字符串的拼接,下面這篇文章主要給大家介紹了關于Java中字符串String的+和+=及循環(huán)操作String原理的相關資料,需要的朋友可以參考下
    2023-01-01
  • 淺談TreeSet中的兩種排序方式

    淺談TreeSet中的兩種排序方式

    下面小編就為大家?guī)硪黄獪\談TreeSet中的兩種排序方式。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • java正則表達式用法大全(深度好文)

    java正則表達式用法大全(深度好文)

    這篇文章主要給大家介紹了關于java正則表達式用法大全的相關資料,正則表達式在處理字符串時非常有用,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • Java之Optional類判空使用及說明

    Java之Optional類判空使用及說明

    這篇文章主要介紹了Java之Optional類判空使用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2026-06-06
  • 詳解Spring?中?Bean?對象的存儲和取出

    詳解Spring?中?Bean?對象的存儲和取出

    由于?Spring?擁有對象的管理權(quán),所以我們也需要擁有較為高效的對象存儲和取出的手段,下面我們來分別總結(jié)一下,對Spring?中?Bean?對象的存儲和取出知識感興趣的朋友跟隨小編一起看看吧
    2022-11-11

最新評論

湾仔区| 闸北区| 集安市| 措美县| 宁远县| 洛隆县| 宜春市| 长子县| 德阳市| 茶陵县| 临西县| 清丰县| 开封市| 兴山县| 封开县| 德化县| 寻甸| 深泽县| 灵石县| 南木林县| 晴隆县| 柯坪县| 左权县| 延边| 翁牛特旗| 新干县| 巩留县| 会昌县| 大安市| 河间市| 中阳县| 汤阴县| 福州市| 灵璧县| 离岛区| 宣汉县| 洪泽县| 涞源县| 乐业县| 宽城| 龙里县|