java運(yùn)行機(jī)制之編譯期、運(yùn)行期和半編譯半解釋性詳解
前言
Java 的生命周期設(shè)計(jì)之所以經(jīng)典,核心在于它采用了 “半編譯,半解釋” 的混合模式。
要真正做到“有深度”地理解 Java 的編譯期和運(yùn)行期,需要深入到 前端編譯(javac) 和 后端編譯/執(zhí)行(JIT/JVM) 的底層工作流與優(yōu)化策略中。
如果從程序執(zhí)行模型來(lái)看,編程語(yǔ)言大致可以分為三類(lèi):
- 純編譯型語(yǔ)言:提前編譯為機(jī)器碼,運(yùn)行速度極快,但跨平臺(tái)能力較差;
- 純解釋型語(yǔ)言:運(yùn)行時(shí)逐行解釋執(zhí)行,靈活性強(qiáng),但性能較低;
- 半編譯半解釋型語(yǔ)言:先編譯為中間字節(jié)碼,再由虛擬機(jī)動(dòng)態(tài)執(zhí)行與優(yōu)化。
Java 并不會(huì)像 C/C++ 那樣直接編譯為特定平臺(tái)的機(jī)器碼,而是先通過(guò) javac 編譯器將源碼編譯為 跨平臺(tái)字節(jié)碼(Bytecode),再交由 JVM(Java Virtual Machine)在不同平臺(tái)上運(yùn)行。
在運(yùn)行過(guò)程中,JVM 又結(jié)合了:
- 解釋執(zhí)行(Interpreter)
- 即時(shí)編譯(JIT, Just-In-Time Compiler)
兩種機(jī)制。
程序啟動(dòng)初期通過(guò)解釋執(zhí)行保證快速啟動(dòng);而高頻運(yùn)行的熱點(diǎn)代碼,則會(huì)被 JIT 編譯為本地機(jī)器碼并緩存,從而獲得接近 C/C++ 的運(yùn)行性能。
也正因?yàn)槿绱?,Java 才真正實(shí)現(xiàn)了著名的:
Write Once, Run Anywhere(一次編寫(xiě),到處運(yùn)行)
本文從 編譯期、運(yùn)行期、JVM 執(zhí)行機(jī)制、JIT 優(yōu)化以及三種語(yǔ)言執(zhí)行模型 等多個(gè)維度,簡(jiǎn)單梳理 Java 的運(yùn)行機(jī)制與底層原理。
一、 編譯期
Java 的編譯期通常指的是前端編譯,即由 javac 編譯器將 .java 源代碼文件轉(zhuǎn)化為 .class 字節(jié)碼文件的過(guò)程。
這個(gè)階段的核心目標(biāo)是:校驗(yàn)語(yǔ)言規(guī)范、轉(zhuǎn)換語(yǔ)法結(jié)構(gòu),但不做深度的性能優(yōu)化。
1.1 核心機(jī)制
編譯期的主要工作不是優(yōu)化性能,而是將 .java 源碼轉(zhuǎn)換為符合 JVM 規(guī)范的 .class 字節(jié)碼。
javac的運(yùn)行機(jī)制如下
解析與填充符號(hào)表 :
將源代碼字符流轉(zhuǎn)變?yōu)闃?biāo)記(Token),構(gòu)造出抽象語(yǔ)法樹(shù)(AST)。此時(shí)如果漏掉分號(hào),就會(huì)報(bào)語(yǔ)法錯(cuò)誤。
注解處理 :
編譯器允許自定義的注解處理器去掃描和修改 AST。
Lombok 就是在此階段大顯身手,強(qiáng)行插入
getter/setter節(jié)點(diǎn),隨后編譯器基于修改后的 AST 重新編譯。語(yǔ)義分析:
檢查變量是否聲明、類(lèi)型是否匹配。進(jìn)行常量折疊(Constant Folding)(如
int a = 1 + 2;直接變成3)。字節(jié)碼生成與解語(yǔ)法糖 :
JVM 不認(rèn)識(shí)語(yǔ)法糖(如增強(qiáng) for、變長(zhǎng)參數(shù)),
javac會(huì)將其還原。例如泛型的類(lèi)型擦除(Type Erasure)就在此發(fā)生,
List<String>會(huì)被擦除為List。最終,AST 被轉(zhuǎn)換為字節(jié)碼指令寫(xiě)入
.class文件。

1.2 方法重載
靜態(tài)類(lèi)型檢查: 編譯器嚴(yán)格按照變量的聲明類(lèi)型進(jìn)行校驗(yàn)。
如果代碼中有多個(gè)同名方法(方法重載 Overload),該調(diào)哪個(gè)?
- 決策邏輯: 編譯器完全根據(jù)傳入?yún)?shù)的聲明類(lèi)型(靜態(tài)類(lèi)型)來(lái)決定。
- 結(jié)果: 編譯器一旦匹配到最合適的重載方法,就會(huì)將這個(gè)確定的符號(hào)引用硬編碼寫(xiě)進(jìn)
.class文件的字節(jié)碼中。重載的決斷,在編譯期就已經(jīng)徹底鎖死。
class Animal {}
class Dog extends Animal {}
public class Test {
// 【方法重載 Overload】
public void feed(Animal a) { System.out.println("Feeding an animal..."); }
public void feed(Dog d) { System.out.println("Feeding a dog..."); }
public static void main(String[] args) {
// 靜態(tài)類(lèi)型: Animal, 實(shí)際類(lèi)型: Dog
Animal myPet = new Dog();
Test test = new Test();
// 提問(wèn):這里會(huì)輸出什么?
test.feed(myPet);
}
}
底層執(zhí)行流程:
- 編譯期: 編譯器看到
test.feed(myPet)。它檢查myPet的靜態(tài)類(lèi)型(Animal),于是匹配到了feed(Animal a),并將該符號(hào)引用寫(xiě)入字節(jié)碼。 - 運(yùn)行期(實(shí)干家): JVM 執(zhí)行時(shí),看到字節(jié)碼指令要求調(diào)用
feed(Animal a),直接執(zhí)行。它不會(huì)在此刻因?yàn)?myPet實(shí)際上是個(gè)Dog而去反悔重選。 - 最終輸出:
Feeding an animal...
二、 運(yùn)行期
運(yùn)行期是 Java 最為復(fù)雜和體現(xiàn)技術(shù)深度的部分。 當(dāng)類(lèi)加載器將 .class 文件讀入內(nèi)存后,JVM(java虛擬機(jī))開(kāi)始接管一切。
運(yùn)行期(由 JVM 和 JIT 編譯器主導(dǎo))它生存在一個(gè)動(dòng)態(tài)的世界里,眼中只有堆內(nèi)存里等號(hào)右邊的真實(shí)對(duì)象。
2.1 核心機(jī)制
- 動(dòng)態(tài)類(lèi)加載機(jī)制:
- 字節(jié)碼被加載進(jìn)方法區(qū)(Metaspace),在“解析”階段,JVM 會(huì)將常量池中的符號(hào)引用替換為直接引用(內(nèi)存指針)。
- 對(duì)于多態(tài)方法,這個(gè)解析會(huì)推遲到真正運(yùn)行時(shí)才進(jìn)行(動(dòng)態(tài)綁定)。
- 混合模式 (Interpreter + JIT):
- 解釋器 (Interpreter):
- 程序剛啟動(dòng)時(shí),JVM 的解釋器會(huì)逐條讀取字節(jié)碼,將其翻譯成當(dāng)前操作系統(tǒng)認(rèn)識(shí)的機(jī)器碼并執(zhí)行。
- 作用: 保證程序能瞬間啟動(dòng),不需要等待漫長(zhǎng)的全量編譯時(shí)間。
- 即時(shí)編譯器 (JIT - Just-In-Time):
- 性能優(yōu)化關(guān)鍵:當(dāng)它發(fā)現(xiàn)某一段代碼(比如某個(gè)方法、某個(gè)大循環(huán))被極其頻繁地調(diào)用時(shí),它會(huì)把這段代碼標(biāo)記為“熱點(diǎn)代碼(Hot Spot)”。
- JIT 會(huì)將其編譯為本地機(jī)器碼(C1 編譯器做局部?jī)?yōu)化,C2 編譯器做激進(jìn)優(yōu)化)。
- 下次再走到這段代碼時(shí),JVM 直接執(zhí)行緩存的機(jī)器碼,速度提升。
- 解釋器 (Interpreter):

2.2 多態(tài)
運(yùn)行期的動(dòng)態(tài)特性開(kāi)始顯現(xiàn):如何實(shí)現(xiàn)多態(tài)(方法重寫(xiě) Override)?
- 決策邏輯: JVM 無(wú)視變量的聲明類(lèi)型,直接去堆內(nèi)存中找對(duì)象的實(shí)際類(lèi)型。
- 執(zhí)行過(guò)程: JVM 查該實(shí)際類(lèi)型對(duì)象的虛方法表(vtable)。如果在子類(lèi)中找到了重寫(xiě)的方法,就執(zhí)行子類(lèi)的邏輯;否則順著繼承鏈往上找。這就是 Java 實(shí)現(xiàn)多態(tài)的底層基石。
// 1. 定義頂層父類(lèi)
class Animal {
public void speak() {
System.out.println("Animal vtable: [speak() -> Animal.speak()] : 動(dòng)物發(fā)出未知的叫聲");
}
}
// 2. 定義子類(lèi) Dog:【重寫(xiě)】了 speak 方法
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Dog vtable: [speak() -> Dog.speak()] : 汪汪汪!(執(zhí)行了子類(lèi)邏輯)");
}
}
// 3. 定義子類(lèi) Bird:【沒(méi)有重寫(xiě)】 speak 方法
class Bird extends Animal {
public void fly() {
System.out.println("鳥(niǎo)兒在飛翔...");
}
// 注意:這里沒(méi)有重寫(xiě) speak() 方法
}
// 4. 測(cè)試主類(lèi)
public class VTableTest {
public static void main(String[] args) {
System.out.println("====== 多態(tài)與虛方法表測(cè)試開(kāi)始 ======\n");
/* * 場(chǎng)景 :JVM 無(wú)視聲明類(lèi)型 (Animal),直接找實(shí)際類(lèi)型 (Dog)
*/
Animal myDog = new Dog(); // 聲明類(lèi)型: Animal, 實(shí)際類(lèi)型: Dog
System.out.print("調(diào)用 myDog.speak() ---> ");
// JVM 去堆內(nèi)存找 myDog 的實(shí)際對(duì)象頭,查 Dog 類(lèi)的 vtable
// 在 Dog 類(lèi)的 vtable 中找到了重寫(xiě)的 speak(),直接執(zhí)行!
myDog.speak();
System.out.println("--------------------------------------------------");
/* * 場(chǎng)景 :順著繼承鏈往上找
*/
Animal myBird = new Bird(); // 聲明類(lèi)型: Animal, 實(shí)際類(lèi)型: Bird
System.out.print("調(diào)用 myBird.speak() ---> ");
// JVM 去堆內(nèi)存找 myBird 的實(shí)際對(duì)象頭,查 Bird 類(lèi)的 vtable
// 發(fā)現(xiàn) Bird 類(lèi)并沒(méi)有重寫(xiě) speak(),查表落空!
// 觸發(fā)機(jī)制:順著繼承鏈往上找,查到 Animal 類(lèi)的 vtable 中有 speak(),執(zhí)行父類(lèi)邏輯!
myBird.speak();
System.out.println("\n====== 測(cè)試結(jié)束 ======");
}
}
代碼運(yùn)行時(shí)底層流程:
1. 當(dāng)執(zhí)行 myDog.speak() 時(shí):
- 編譯期:
javac編譯器只看左邊,確認(rèn)Animal類(lèi)里確實(shí)有speak()方法,于是允許編譯通過(guò),并在字節(jié)碼中寫(xiě)入一條invokevirtual Animal.speak的指令。 - 運(yùn)行期: 執(zhí)行到這條指令時(shí),JVM 的動(dòng)態(tài)特性啟動(dòng)。它根本不管字節(jié)碼里寫(xiě)的是
Animal.speak。它直接去內(nèi)存里找到那個(gè)被new出來(lái)的真正對(duì)象(Dog實(shí)例)。 - 查表: JVM 提取
Dog實(shí)例的對(duì)象頭信息,定位到Dog類(lèi)的虛方法表(vtable)。它發(fā)現(xiàn)表里的speak指針已經(jīng)被替換成了Dog自己實(shí)現(xiàn)的方法地址。于是,輸出“汪汪汪”。
2. 當(dāng)執(zhí)行 myBird.speak() 時(shí):
- 編譯期: 同樣順利通過(guò)。
- 運(yùn)行期: JVM 找到內(nèi)存里真正的
Bird實(shí)例。 - 查表與回溯: JVM 查看
Bird類(lèi)的虛方法表。但是,因?yàn)?Bird類(lèi)沒(méi)有寫(xiě)@Override public void speak(),所以在這個(gè)表里,speak指針依然原封不動(dòng)地指向著父類(lèi)Animal的speak方法的地址。 - 結(jié)果: 于是 JVM 只能“順藤摸瓜”,執(zhí)行了父類(lèi)的方法,輸出“動(dòng)物發(fā)出未知的叫聲”。這也就是你提到的:“否則順著繼承鏈往上找”。
三、java代碼的編譯和運(yùn)行
3.1 編譯期:Java 源碼 → 跨平臺(tái)字節(jié)碼
對(duì)應(yīng)圖中綠色區(qū)域,是脫離 JVM 的前置編譯環(huán)節(jié),核心是把人類(lèi)可讀的 Java 源碼,轉(zhuǎn)為 JVM 可識(shí)別的統(tǒng)一標(biāo)準(zhǔn)格式。
- 輸入:Java 源碼文件(
.java) - 核心處理:通過(guò)**
javac**等 Java 編譯器完成 4 步標(biāo)準(zhǔn)化操作:- 解析源碼生成抽象語(yǔ)法樹(shù)(AST)、填充符號(hào)表
- 注解處理(如 Lombok 等插件的攔截增強(qiáng))
- 語(yǔ)義分析(常量折疊、語(yǔ)法校驗(yàn),確保代碼邏輯合法)
- 生成字節(jié)碼、解語(yǔ)法糖(如 foreach、泛型擦除等簡(jiǎn)化語(yǔ)法的還原)
- 輸出:Java 字節(jié)碼文件(
.class)- 關(guān)鍵特性:字節(jié)碼不綁定任何操作系統(tǒng)、CPU 架構(gòu),是 JVM 專(zhuān)屬的跨平臺(tái)統(tǒng)一指令集,是 Java 實(shí)現(xiàn)跨平臺(tái)能力的核心基礎(chǔ)。
3.2 運(yùn)行期:字節(jié)碼 → 機(jī)器碼 → 硬件執(zhí)行
對(duì)應(yīng)圖中紅色 JVM 區(qū)域,是代碼真正執(zhí)行的核心環(huán)節(jié),全流程在 JVM 中完成,最終落地到操作系統(tǒng)和底層硬件。
完整執(zhí)行鏈路如下:
類(lèi)加載環(huán)節(jié):
.class字節(jié)碼通過(guò)文件系統(tǒng) / 網(wǎng)絡(luò)進(jìn)入 JVM,由類(lèi)加載器完成加載→驗(yàn)證→準(zhǔn)備→解析→初始化全流程,將字節(jié)碼加載到 JVM 內(nèi)存中,生成可執(zhí)行的類(lèi)結(jié)構(gòu)。
混合模式執(zhí)行(JVM 核心設(shè)計(jì))
類(lèi)加載完成后,JVM 采用「解釋執(zhí)行 + JIT 編譯」的雙路徑執(zhí)行,平衡啟動(dòng)速度與峰值性能:
解釋執(zhí)行:由 Java 解釋器逐行翻譯字節(jié)碼為機(jī)器碼,翻譯完成立即執(zhí)行。優(yōu)勢(shì)是啟動(dòng)快、無(wú)編譯等待開(kāi)銷(xiāo),保證跨平臺(tái)兼容性,是程序啟動(dòng)初期的主要執(zhí)行方式。
JIT 即時(shí)編譯:運(yùn)行時(shí) JVM 會(huì)識(shí)別高頻執(zhí)行的「熱點(diǎn)代碼」(如循環(huán)、頻繁調(diào)用的方法),由 C1/C2 JIT 編譯器完成深度優(yōu)化(方法內(nèi)聯(lián)、逃逸分析、標(biāo)量替換等),一次性編譯為本地機(jī)器碼并緩存,后續(xù)執(zhí)行直接調(diào)用,無(wú)需重復(fù)翻譯,峰值性能無(wú)限接近 C/C++ 等純編譯型語(yǔ)言。
最終落地:解釋器 / JIT 生成的機(jī)器碼,交由操作系統(tǒng)調(diào)度,最終在底層 CPU 硬件上完成執(zhí)行。

四、java的語(yǔ)言特性
4.1 純編譯型語(yǔ)言
提前全量靜態(tài)編譯,直接生成目標(biāo)平臺(tái)專(zhuān)屬機(jī)器碼,運(yùn)行時(shí)無(wú)額外翻譯,CPU可直接執(zhí)行,無(wú)中間層開(kāi)銷(xiāo)。
- 開(kāi)發(fā)階段:編寫(xiě)源代碼(如C的
.c、C++的.cpp文件)。 - 全量編譯階段:通過(guò)編譯器(GCC/Clang/MSVC)完成「預(yù)編譯→編譯→匯編→鏈接」,生成當(dāng)前操作系統(tǒng)+CPU架構(gòu)專(zhuān)屬的可執(zhí)行文件(Windows的
.exe、Linux的ELF等),內(nèi)含純機(jī)器碼。 - 運(yùn)行階段:操作系統(tǒng)直接加載可執(zhí)行文件到內(nèi)存,CPU逐條執(zhí)行機(jī)器碼,全程無(wú)翻譯。
核心優(yōu)缺點(diǎn):
| 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|
| 運(yùn)行性能最快,無(wú)運(yùn)行時(shí)開(kāi)銷(xiāo) | 跨平臺(tái)性極差,需按平臺(tái)單獨(dú)編譯 |
| 內(nèi)存完全可控,無(wú)額外運(yùn)行時(shí)內(nèi)存占用 | 編譯耗時(shí)久,代碼改動(dòng)需重新編譯 |
| 可做極致靜態(tài)編譯優(yōu)化 | 開(kāi)發(fā)門(mén)檻高,需手動(dòng)處理內(nèi)存、指針等底層細(xì)節(jié) |
代表語(yǔ)言與適用場(chǎng)景
- 代表語(yǔ)言:C、C++、Rust、Go、Swift、匯編
- 適用場(chǎng)景:對(duì)性能、延遲要求極高的領(lǐng)域,如操作系統(tǒng)內(nèi)核、嵌入式開(kāi)發(fā)、游戲引擎、高頻交易系統(tǒng)。
4.2 純解釋型語(yǔ)言
無(wú)提前全量編譯,運(yùn)行時(shí)由解釋器逐行翻譯源代碼為機(jī)器碼并執(zhí)行,不生成獨(dú)立可執(zhí)行文件,也不緩存翻譯結(jié)果,靈活性高但性能犧牲大。
- 開(kāi)發(fā)階段:編寫(xiě)源代碼(如早期Python的
.py、Shell的.sh文件),直接分發(fā)源碼。 - 運(yùn)行階段:目標(biāo)機(jī)器需安裝對(duì)應(yīng)解釋器;解釋器逐行讀取源碼,實(shí)時(shí)翻譯為機(jī)器碼并執(zhí)行,不緩存翻譯結(jié)果。
核心優(yōu)缺點(diǎn)
| 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|
| 極致源代碼跨平臺(tái),同一份代碼有解釋器即可運(yùn)行 | 運(yùn)行性能極差,通常比純編譯型慢10-100倍 |
| 開(kāi)發(fā)效率極高,無(wú)需編譯、改完即跑 | 必須依賴(lài)解釋器,無(wú)對(duì)應(yīng)環(huán)境無(wú)法執(zhí)行 |
| 動(dòng)態(tài)性拉滿(mǎn),運(yùn)行時(shí)可隨意修改代碼邏輯、變量類(lèi)型 | 無(wú)法提前靜態(tài)優(yōu)化,運(yùn)行時(shí)才暴露語(yǔ)法、類(lèi)型錯(cuò)誤 |
代表語(yǔ)言與適用場(chǎng)景
- 代表語(yǔ)言(經(jīng)典純解釋實(shí)現(xiàn)):早期Python、早期JavaScript、Shell腳本、BASIC
- 補(bǔ)充說(shuō)明:現(xiàn)代主流腳本語(yǔ)言已脫離純解釋模型(如CPython預(yù)編譯為
.pyc、V8引入JIT),本質(zhì)為半編譯半解釋。 - 適用場(chǎng)景:自動(dòng)化運(yùn)維腳本、快速原型驗(yàn)證、網(wǎng)頁(yè)前端交互、輕量工具開(kāi)發(fā)。
4.3 半編譯半解釋型語(yǔ)言
為解決「編譯型跨平臺(tái)差、解釋型性能差」的矛盾誕生,結(jié)合兩者優(yōu)勢(shì):先通過(guò)前端編譯器將源碼編譯為跨平臺(tái)中間碼(字節(jié)碼),運(yùn)行時(shí)由目標(biāo)平臺(tái)虛擬機(jī)通過(guò)「解釋執(zhí)行+即時(shí)編譯」混合模式轉(zhuǎn)為機(jī)器碼執(zhí)行,實(shí)現(xiàn)“一次編寫(xiě),到處運(yùn)行”。
分為編譯期和運(yùn)行期兩大階段:
編譯期(一次編寫(xiě)的核心)
開(kāi)發(fā)階段:編寫(xiě)Java源代碼(
.java文件)。前端編譯:通過(guò)
javac編譯器將源碼一次性編譯為跨平臺(tái)字節(jié)碼文件(.class)。- 關(guān)鍵特性:字節(jié)碼不綁定操作系統(tǒng)、CPU架構(gòu),是JVM專(zhuān)屬統(tǒng)一指令集,同一份字節(jié)碼在所有平臺(tái)一致,是跨平臺(tái)核心基礎(chǔ)。
運(yùn)行期(到處運(yùn)行的核心)
目標(biāo)機(jī)器需安裝對(duì)應(yīng)平臺(tái)的JVM虛擬機(jī)(Windows/Linux/macOS均有專(zhuān)屬JVM,適配底層系統(tǒng)和硬件)。
類(lèi)加載:JVM把
.class字節(jié)碼加載到內(nèi)存,完成驗(yàn)證、準(zhǔn)備、解析等流程。混合模式執(zhí)行(平衡啟動(dòng)速度與峰值性能):
- 解釋執(zhí)行:程序啟動(dòng)初期,逐行翻譯字節(jié)碼為機(jī)器碼執(zhí)行,保證快速啟動(dòng)與跨平臺(tái)兼容。
- JIT即時(shí)編譯:運(yùn)行時(shí)識(shí)別高頻「熱點(diǎn)代碼」(如循環(huán)、頻繁調(diào)用的方法),一次性全量編譯為本地機(jī)器碼并緩存,后續(xù)執(zhí)行直接調(diào)用,無(wú)需重復(fù)翻譯,峰值性能無(wú)限接近純編譯型語(yǔ)言。

核心優(yōu)缺點(diǎn)
| 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|
| 真正跨平臺(tái):同一份字節(jié)碼,有對(duì)應(yīng)JVM即可運(yùn)行,無(wú)需按平臺(tái)修改、重編譯 | 有啟動(dòng)開(kāi)銷(xiāo):JVM啟動(dòng)、類(lèi)加載、解釋執(zhí)行有固定開(kāi)銷(xiāo),不適合超短生命周期程序(如簡(jiǎn)單腳本) |
| 高性能:JIT即時(shí)編譯優(yōu)化,熱點(diǎn)代碼性能接近C/C++,遠(yuǎn)超純解釋型語(yǔ)言 | 強(qiáng)依賴(lài)運(yùn)行環(huán)境:目標(biāo)機(jī)器需安裝對(duì)應(yīng)版本JVM,原生無(wú)法生成獨(dú)立可執(zhí)行文件(GraalVM可實(shí)現(xiàn),非原生能力) |
| 內(nèi)存安全、開(kāi)發(fā)效率高:JVM自帶GC自動(dòng)回收內(nèi)存,無(wú)需手動(dòng)管理,規(guī)避內(nèi)存泄漏、野指針問(wèn)題 | 內(nèi)存占用更高:JVM本身、GC、運(yùn)行時(shí)數(shù)據(jù)區(qū)均有固定內(nèi)存開(kāi)銷(xiāo) |
| 動(dòng)態(tài)能力強(qiáng):基于字節(jié)碼和JVM實(shí)現(xiàn)反射、動(dòng)態(tài)代理,是Spring等企業(yè)級(jí)框架的核心支撐 | 底層控制能力有限:不適合操作系統(tǒng)內(nèi)核、驅(qū)動(dòng)等硬件級(jí)開(kāi)發(fā) |
代表語(yǔ)言與適用場(chǎng)景
- 代表語(yǔ)言:Java、C#、Kotlin(JVM平臺(tái))、Scala
- 適用場(chǎng)景:企業(yè)級(jí)后端開(kāi)發(fā)、Android開(kāi)發(fā)、大數(shù)據(jù)框架(Hadoop/Spark)、中間件開(kāi)發(fā),是兼顧跨平臺(tái)性、開(kāi)發(fā)效率與高性能的優(yōu)選方案。
4.4 常見(jiàn)誤區(qū)
- 現(xiàn)代Python/JavaScript并非純解釋型語(yǔ)言:CPython會(huì)預(yù)編譯為
.pyc字節(jié)碼,Chrome V8、PyPy均引入JIT編譯,本質(zhì)已屬于半編譯半解釋模型。 - Go/Rust并非半編譯型語(yǔ)言:二者雖帶GC、協(xié)程調(diào)度等運(yùn)行時(shí)能力,但均提前全量編譯為目標(biāo)平臺(tái)機(jī)器碼,運(yùn)行時(shí)無(wú)翻譯環(huán)節(jié),屬于純編譯型語(yǔ)言。
- Java并非固定半編譯半解釋模式:現(xiàn)代JVM默認(rèn)「解釋+JIT」混合模式,可通過(guò)參數(shù)強(qiáng)制純解釋/純編譯;GraalVM支持提前將Java代碼編譯為本地機(jī)器碼,轉(zhuǎn)為純編譯型執(zhí)行。
總結(jié)
Java 的運(yùn)行機(jī)制,本質(zhì)上是一套圍繞 “跨平臺(tái) + 高性能” 而設(shè)計(jì)的動(dòng)態(tài)執(zhí)行體系。
與傳統(tǒng)純編譯型語(yǔ)言不同,Java 并不會(huì)直接生成特定平臺(tái)的機(jī)器碼,而是采用:**“源碼 → 字節(jié)碼 → JVM → 機(jī)器碼”**的分層執(zhí)行模型。
它的本質(zhì)是:
先編譯為跨平臺(tái)字節(jié)碼,再由 JVM 動(dòng)態(tài)解釋與 JIT 編譯執(zhí)行。
因此:
- 編譯型解決性能問(wèn)題
- 解釋型解決跨平臺(tái)問(wèn)題
- JVM/JIT 負(fù)責(zé)在兩者之間尋找平衡
最終形成了 Java 最經(jīng)典的設(shè)計(jì)哲學(xué):
一次編寫(xiě),到處運(yùn)行(Write Once, Run Anywhere)
到此這篇關(guān)于java運(yùn)行機(jī)制之編譯期、運(yùn)行期和半編譯半解釋性詳解的文章就介紹到這了,更多相關(guān)java編譯期、運(yùn)行期和半編譯半解釋性?xún)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot整合gateway實(shí)現(xiàn)網(wǎng)關(guān)功能的示例代碼
本文主要介紹了springboot整合gateway實(shí)現(xiàn)網(wǎng)關(guān)功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
ThreadLocal內(nèi)存泄露的產(chǎn)生原因和處理方法
ThreadLocal 的內(nèi)存泄漏問(wèn)題通常發(fā)生在使用 ThreadLocal 存儲(chǔ)對(duì)象時(shí),尤其是在多線(xiàn)程環(huán)境中,線(xiàn)程池中的線(xiàn)程復(fù)用可能導(dǎo)致一些資源沒(méi)有及時(shí)清理,從而引發(fā)內(nèi)存泄漏,所以本文給大家介紹了ThreadLocal內(nèi)存泄露的產(chǎn)生原因和處理方法,需要的朋友可以參考下2024-12-12
Mybatis-Plus使用saveOrUpdate及問(wèn)題解決方法
本文主要介紹了Mybatis-Plus使用saveOrUpdate及問(wèn)題解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
springBoot整合CXF并實(shí)現(xiàn)用戶(hù)名密碼校驗(yàn)的方法
這篇文章主要介紹了springBoot整合CXF并實(shí)現(xiàn)用戶(hù)名密碼校驗(yàn)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
Java?spring?通過(guò)注解方式創(chuàng)建對(duì)象的示例詳解
這篇文章主要介紹了java?spring?通過(guò)注解方式創(chuàng)建對(duì)象,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02
Nacos客戶(hù)端本地緩存和故障轉(zhuǎn)移方式
Nacos客戶(hù)端在從Server獲得服務(wù)時(shí),若出現(xiàn)故障,會(huì)通過(guò)ServiceInfoHolder和FailoverReactor進(jìn)行故障轉(zhuǎn)移,ServiceInfoHolder緩存服務(wù)信息,FailoverReactor處理故障轉(zhuǎn)移,包括開(kāi)啟故障轉(zhuǎn)移開(kāi)關(guān)、讀取備份文件等2024-12-12
SpringBoot+Apache tika實(shí)現(xiàn)文檔內(nèi)容解析的示例詳解
Apache tika是Apache開(kāi)源的一個(gè)文檔解析工具,本文主要為大家介紹了如何在springboot中引入tika的方式解析文檔,感興趣的小伙伴可以了解一下2023-07-07

