Java類加載那些事

Java源文件(.java文件)被編譯器編譯后變為字節碼形式的類文件(.class文件),Java類加載的過程就是JVM加載.class的二進制文件并且放到內存中,將數據放到方法區,并且在堆區構造一個java.lang.class對象,并且完成類的初始化的過程。

//下述片段引用自?Java的類加載機制是什么?

Java的類加載機制主要分為三個過程:加載、連接和初始化。

1.加載機制

Java的類加載機制主要分為三個過程:加載、連接和初始化。這三個過程的順序是固定的,但是每個過程中的細節卻是不同的。下面我們來詳細介紹一下這三個過程。

1.1 加載

Java的類加載器會根據類的全限定名來加載類,當需要使用某個類時,如果該類還未被加載進內存,則需要執行一下步驟進行加載:

1.1.1. 通過類的全限定名找到對應的class文件,這里的class文件可以是.java文件經過編譯之后生成的.class文件,也可以是通過其他方式生成的.class文件。

1.1.2 將class文件中的二進制數據讀取到內存中,并將其轉換為方法區的運行時數據結構。

1.1.3 創建由該類所屬的java.lang.Class對象。該對象可以理解為,是對類的各種數據(如名稱、訪問修飾符、方法、成員變量等)的封裝。

在加載類時,類加載器除了加載某個具體的類外,還需要將這個類所依賴的類也加入到內存中。這種依賴性是多層級的,也就是說,被依賴的類又可能會去依賴其他類,所以在加載一個類時,通常需要將其類圖中所有的類都加載進來。

1.2 連接

Java虛擬機在加載類之后,需要對類進行連接,連接分為三個步驟:驗證、準備和解析。

1.2.1. 驗證:在這個步驟中,Java虛擬機主要確保所加載的類的正確性。驗證過程主要包括文件格式驗證、元數據驗證、字節碼驗證和符號引用驗證等。其目的在于確保目標.class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機運行時環境安全。

1.2.2. 準備:在準備階段,Java虛擬機為類的靜態變量分配內存,并設置變量的初始值。這里需要注意的是,在這個階段中分配的內存并不包含那些用戶自定義的初始化值,這些值在初始化階段中進行設置。

1.2.3. 解析:Java在這個階段中將常量池中的符號引用轉為直接引用。通過符號引用,虛擬機得知該類訪問其他的類或者類中的字段、方法等,但在類初始化時,需要緩存這些直接引用,以便于直接調用。

1.3 初始化

在類的準備階段,Java虛擬機已經為靜態變量分配了內存并設置了初值,但是這些靜態變量”賦初值“的動作并沒有完成。初始化階段,會為靜態變量設置用戶自定義的初始化值,并執行類構造器<clinit>()方法,以執行初始化操作。

此時,類的準備和初始化階段已經執行結束,Java的類加載機制總的過程也就結束了

//引用結束

注意,靜態代碼的初始化分為兩步,連接的準備階段包含初始化,最后又有一個初始化步驟,兩者并不重疊,前者是給靜態成員變量分配內存并且設置類型的初始值,后者是給靜態成員變量設置用戶指定的初始值。這段話有點拗口,代碼來說明更清晰。

?1、父類 parent.java文件

public class Parent {static {System.out.println("Parent static block 1.");parentStaticIntVar = 3;}static Integer parentStaticIntVar = 2;static {System.out.println("Parent static block 2.");System.out.println("parentStaticIntVar=" + parentStaticIntVar);parentStaticIntVar = 4;}{System.out.println("Parent not static block 1.");parentIntVar = 30;}Integer parentIntVar = 20;public Parent(){	System.out.println("Parent construct  method .");System.out.println("parentIntVar=" + parentIntVar);}public void f(){System.out.println("parent f().");}{System.out.println("Parent not static block 2.");parentIntVar = 40;}}

2、子類 Sub.java文件

public class Sub extends Parent {static {System.out.println("Sub static block 1.");subStaticIntVar = 3;}static Integer subStaticIntVar = 2;static {System.out.println("Sub static block 2.");System.out.println("subStaticIntVar=" + subStaticIntVar);subStaticIntVar = 4;}{System.out.println("Sub not static block 1.");subIntVar = 30;}Integer subIntVar = 20;public Sub(){	System.out.println("Sub construct  method .");System.out.println("subIntVar=" + subIntVar);}public void f(){System.out.println("Sub f().");}{System.out.println("Sub not static block 2.");subIntVar = 40;}}

3、TestMain.java文件

public class TestMain {public static void main(String[] args) {System.out.println("-----class-----");System.out.println(">>>subStaticIntVar=" + Sub.subStaticIntVar);System.out.println(">>>parentStaticIntVar=" + Sub.parentStaticIntVar);System.out.println("-----instance-----");Sub s = new Sub();s.f();}}

4、輸出結果

-----class-----
Parent static block 1.
Parent static block 2.
parentStaticIntVar=2
Sub static block 1.
Sub static block 2.
subStaticIntVar=2
>>>subStaticIntVar=4
>>>parentStaticIntVar=4
-----instance-----
Parent not static block 1.
Parent not static block 2.
Parent construct  method .
parentIntVar=40
Sub not static block 1.
Sub not static block 2.
Sub construct  method .
subIntVar=40
Sub f().

解讀一下后可以知道靜態代碼塊和靜態變量遵循如下規則:

1、靜態代碼塊先于構造方法執行;

2、靜態代碼塊可以給靜態成員變量賦值;

3、靜態代碼塊之間按照先后順序執行;

4、父類的靜態代碼塊先于子類的靜態代碼塊執行;

5、靜態代碼塊先于非靜態代碼塊執行;

6、靜態代碼塊在第一次使用這個類的時候執行,并且只執行一次;

7、靜態變量的顯式賦值和靜態代碼塊的按照先后順序執行;

實際上每個Java源文件由編輯器編譯后,會自動給類加載器追加一個類初始化方法:<clinit>(),一個類只有一個,包含靜態變量的顯式賦值代碼和靜態代碼塊的代碼,在源文件中看起來是一個一個獨立的代碼塊,實際上編譯后都放到一個這個類初始化方法中去了。

非靜態的代碼塊和變量的規則和上述類似。

類加載的方法>>>

1、Class.forName("")

Class<?> c = Class.forName("com.example.zhangzk.reflect.TestServiceImpl");

加載類,并且完成初始化。

2、ClassLoader.loadClass("")

Class<?> c = Thread.currentThread().getContextClassLoader().loadClass("com.example.zhangzk.reflect.TestServiceImpl");

加載類,不初始化。

加載器有哪些>>>

啟動類加載器,C++編寫的,進入Java世界的大門,負責加載存放在$JAVA_HOME\jre\lib下,或被-Xbootclasspath參數指定的路徑中的,并且能被虛擬機識別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader加載)。

擴展類加載器,Java編寫的,父加載器為啟動類加載器,該加載器由sun.misc.Launcher$ExtClassLoader實現,它負責加載$JAVA_HOME\jre\lib\ext目錄中,或者由java.ext.dirs系統變量指定的路徑中的所有類庫(如javax.*開頭的類)。

應用程序類加載器,Java編寫的,父加載器為擴展類加載器,該類加載器由sun.misc.Launcher$AppClassLoader來實現,它負責加載用戶類路徑(ClassPath)所指定的類,開發者可以直接使用該類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

自定義類加載器,Java編寫的,父加載器為應用程序類加載器,典型代表是Tomcat,為了在一個TOMCAT進程下部署多個JAVA應用程序必須要自定義類加載器,進行應用隔離。

雙親委派模型>>>

每個類加載器需要加載類的時候,先請求父類加載器來加載,一直到啟動類加載器,啟動類加載器是沒有父類加載器的,父類加載器找不到給類才由自己來加載。

要想搞清楚Spring Boot的啟動流程,必須要要知道上述區別,只有充分利用好上述差異才能精準的控制加載和初始化的過程,Spring中這些都用的出神入化了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/164587.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/164587.shtml
英文地址,請注明出處:http://en.pswp.cn/news/164587.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態規劃從入門到精通

目錄 動態規劃的詳解 動態規劃的應用 機器人到達指定位置數 換錢的最少貨幣數 排成一條線的紙牌博弈問題 象棋中馬的跳法 Bob的生存概率 換錢的方法數 動態規劃的總結 動態規劃的詳解 暴力嘗試遞歸操作中有很多重復計算的操作&#xff0c;浪費時間。動態規劃就是減少暴力…

大模型增量預訓練參數說明

在增量預訓練過程中通常需要設置三類或四類參數,模型參數,數據參數,訓練參數,額外參數。 下面分別針對這四種參數進行說明。 歡迎關注公眾號 模型參數 model_type模型類型,例如bloom,llama,baichuan,qwen等。 model_name_or_path模型名稱或者路徑。 tokenizer_name_or…

JS數組常用的20種方法詳解(每一個方法都有例子,超全面,超好理解的教程,干貨滿滿)

目錄 1.會改變原數組的方法&#xff08;7種&#xff09; 1.push() 2.pop() 3.unshift() 4.shift() 5.reverse() 6.sort() 7.splice() 2.不改變原數組的方法&#xff08;13種&#xff0c;返回的新數組是從原數組淺拷貝來的&#xff09; 1.concat() 2.join() 3.slice…

12個最佳WordPress投票插件

您是否正在為您的網站尋找WordPress投票插件&#xff1f; WordPress投票插件可讓您輕松地在您的網站上進行民意調查&#xff0c;用戶可以投票。這是在收集見解的同時建立用戶參與度的有效策略。 在本文中&#xff0c;我們精心挑選了最好的WordPress投票插件&#xff0c;可幫助…

代碼隨想錄算法訓練營第五十二天|300.最長遞增子序列 674. 最長連續遞增序列 718. 最長重復子數組

文檔講解&#xff1a;代碼隨想錄 視頻講解&#xff1a;代碼隨想錄B站賬號 狀態&#xff1a;看了視頻題解和文章解析后做出來了 300.最長遞增子序列 class Solution: # 2516 ms, faster than 64.96%def lengthOfLIS(self, nums: List[int]) -> int:n len(nums)dp [1] * n…

從Discord的做法中學習 — 使用Golang進行請求合并

正如你可能之前看到的&#xff0c;Discord去年發布了一篇有價值的文章&#xff0c;討論了他們成功存儲了數萬億條消息。雖然有很多關于這篇文章的YouTube視頻和文章&#xff0c;但我認為這篇文章中一個名為“數據服務為數據服務”的部分沒有得到足夠的關注。在這篇文章中&#…

QT項目移植到VS+QT(RTI-DDS)

QT中.pro文件中include(./xxx.pri) pri文件如下定義 unset(FILENAMES)for(FILENAME, FILENAMES) {HEADERFILE $$PWD/$${FILENAME}.hif(exists($$HEADERFILE)) {HEADERS * $$HEADERFILE}SOURCEFILE $$PWD/$${FILENAME}.cppif(exists($$SOURCEFILE)) {SOURCES * $$SOURCEFILE}…

CSS-鼠標屬性篇

屬性名&#xff1a;cursor 功能&#xff1a;設置鼠標光標的樣式 屬性值&#xff1a; pointer&#xff1a;小手move&#xff1a;移動圖標text&#xff1a;文字選擇器crosshair&#xff1a;十字架wait&#xff1a;等待help&#xff1a;幫助 eg.html{ cursor: wait;}(此處使用css改…

SpringBoot——MVC原理

優質博文&#xff1a;IT-BLOG-CN 一、SpringMVC自動配置 SpringMVC auto-configuration&#xff1a;SpringBoot自動配置好了SpringMVC。以下是SpringBoot對SpringMVC的默認配置&#xff1a;[WebMvcAutoConfiguration] 【1】包括ContentNegotiatingViewResolver和BeanNameView…

Keil工程打開發現目標芯片無法選擇解決方案

買了一個開發板&#xff0c;配套有一些底層驅動的例程&#xff0c;打開后發現目標芯片無法選擇&#xff0c;對應的下載Flash FLM文件也無法選擇。從提示框中可以知道所提供的例程是Keil4的例程&#xff0c;我電腦上安裝的Keil版本是Keil版本&#xff0c;估計是這個原因導致工程…

C# 執行Excel VBA宏工具類

寫在前面 在Excel文檔的自動化處理流程中&#xff0c;有部分值需要通過已定義的宏來求解&#xff0c;所以延伸出了用C# 調用Excel中的宏代碼的需求。 首先要從NuGet中引入Microsoft.Office.Interop.Excel 類庫 using Excel Microsoft.Office.Interop.Excel; 代碼實現 /// &l…

HashMap,1.7與1.8的區別,HashMap的擴容方式有哪些

HashMap,1.7與1.8的區別 底層數據結構的區別 JDK 1.8之前&#xff1a; 1&#xff09;JDK1.8 之前HashMap 底層是數組和鏈表結合在一起使用也就是鏈表散列。 2&#xff09;HashMap 通過key 的hashCode 經過擾動函數處理過后得到hash 值&#xff0c;然后通過(n - 1&#xff09…

修改el-radio-group樣式,自定義單選組件

修改el-radio-group樣式,自定義單選組件 自定義組件 MyRadioGroup.vue <template><div class"btnsBox"><el-radio-group v-model"activeIndex" change"handleClick"><el-radio-buttonv-for"(item, index) in list&qu…

CSS3動畫

在CSS3中新增了一個很有意思的東西&#xff0c;那就是動畫&#xff0c;有了動畫我們可以做很多的事情&#xff0c;讓我為大家介紹一下動畫吧&#xff01; 本篇文章關于介紹動畫&#xff0c;利用小球移動為你們介紹一下動畫 默認樣式&#xff1a; <!DOCTYPE html> <ht…

普通話考試相關(一文讀懂)

文章目錄&#xff1a; 一&#xff1a;相關常識 1.考試報名時間 2.報名地方 費用 證件 3.考試流程 4.普通話等級說明 二&#xff1a;題型 三&#xff1a;技巧 1.前三題 2.命題說話 四&#xff1a;普通話考試題庫 1.在線題庫 2.下載題庫 一&#xff1a;相關常識 …

JavaEE(SpringMVC)期末復習

文章目錄 JavaEE期末復習一、單選題&#xff1a; JavaEE期末復習 一、單選題&#xff1a; 1.Spring的核?技術是&#xff08; A &#xff09;&#xff1f; A依賴注入 B.JdbcTmplate C.聲明式事務 D.資源訪問 Spring的核心技術包括依賴注入&#xff08;Dependency Injection&am…

【前端】js通過canvas獲取瀏覽器的唯一指紋可以當做唯一標識

【前端】js通過canvas獲取瀏覽器的唯一指紋可以當做唯一標識 <!DOCTYPE html> <html><head> <meta charset"utf-8" /> <meta name"viewport" content"widthdevice-width" /> <title>JS Bin</title> &…

解決Emmy Lua插件在IDEA或 Reder 沒有代碼提示的問題(設置文件關聯 增加對.lua.txt文件的支持)

目錄 Reder版本2019.x Reder版本2021.1.5x Reder版本2019.x 解決Emmy Lua插件在IDEA或 Reder 沒有代碼提示的問題(設置文件關聯 增加對.lua.txt文件的支持) Reder版本2021.1.5x 解決Emmy Lua插件在IDEA或 Reder 沒有代碼提示的問題(設置文件關聯 增加對.lua.txt文件的支持)…

java游戲制作-王者榮耀游戲

一.準備工作 首先創建一個新的Java項目命名為“王者榮耀”&#xff0c;并在src下創建兩個包分別命名為“com.sxt"、”com.stx.beast",在相應的包中創建所需的類。 創建一個名為“img”的文件夾來儲存所需的圖片素材。 二.代碼呈現 package com.sxt;import javax.sw…

Netty Review - 探索ByteBuf的內部機制

文章目錄 概念ByteBuf VS Java NIO BufferByteBuf實現類HeapByteBuf vs DirectByteBufPooledByteBuf vs UnpooledByteBuf其他 ByteBuf的實現機制 概念 ByteBuf是Netty中用于處理二進制數據的緩沖區 Netty的ByteBuf是一個可用于高效存儲和操作字節數據的數據結構。與傳統的Byt…