Java源碼的前端編譯

Java源碼的前端編譯


歡迎來到我的博客:TWind的博客

我的CSDN::Thanwind-CSDN博客

我的掘金:Thanwinde 的個人主頁


0.前言

當一份Java代碼寫好時,將其進行編譯,運行,并不是簡單把這個Java源碼從頭到尾執行,一般來說會經歷前端編譯和后端編譯兩個階段,前端編譯會把Java源碼進行分析,拆解,填充并進行一些優化來變成字節碼

后端編譯是發生在JVM已經在解釋執行字節碼時的JIT,會進行一些分析來將熱點代碼直接替換成大部分情況下效率更高的本地機器碼,并進行許多優化,從而提高效率

除去前后編譯,還有提前編譯,后面都會寫文章一一介紹


1.前端編譯階段

前端編譯是一個Java源碼的開始,在這里會將其轉化為可以執行(效率不談)的字節碼

Javac

Javac是收錄于JDK中的Java編譯器。該工具可以將后綴名為.java的源文件編譯為后綴名為.class的可以運行于JVM的字節碼,Javac是由Java寫的,運行javac的實質便是命令行的調用:javac hello.java

Java對于如何把.java文件轉化為.class文件規范得很寬松,可能會導致class在一些JDK上能編譯,一些卻不行的情況

具體來說,Javac的編譯過程可分為四個階段

  • 初始化插入式注解處理器
  • 解析與填充符號表
    • 把源代碼轉化為標記集合來構造抽象語法樹
    • 填充符號表
  • 注解處理器處理注解
  • 語義分析與生成字節碼
    • 標注檢查
    • 數據流與控制流分析
    • 解語法糖
    • 字節碼生成

下面,讓我們一個個來看:


初始化插入式注解處理器

JDK5之后,Java提供了對注解的支持,原本的方案是把注解作為運行時才發揮作用的,但是到了JDK6,引入了插入式注解處理器:讓注解處理可以發生在編譯階段,一般來說,運行時的注解只能完成一些反射,自動化類的操作,但注解處理時可以動態的向其中加入代碼:譬如lombok之類的動態生成代碼,使注解能在代碼層面影響代碼

SPI

許多的框架其實都是依靠于這套機制完成的,而這些是基于一種名為 SPI 的技術

和SPI對應的是API,API(Application Programming Interface)

在這里插入圖片描述

API就是上方:實現方已經實現了接口,要求調用方去實現它

SPI反過來:接口由調用方決定,實現方要根據調用方的接口要求去實現這個接口來提供服務

API最典型的實現就是OAuth2服務:你需要按照OAuth2提供商的要求去實現登錄過程

SPI最典型的也就是JDBC,日志:各種數據庫的JDBC驅動都是按照統一的接口規范來編寫的,完全符合調用者制定的規范,眾多的日志實現類也同理

但這只是SPI的概念,和Java中修改源代碼的需求好像并無交集

具體來說,Java設計了許多接口,來供其他包作者去適配

這其中就包括注解的解釋接口:javax.annotation.processing.AbstractProcessor,或是javax.annotation.processing.Processor(插入式注解處理器會放在META-INF/services之中)

在編譯的時候,也就是一開始編譯,Javac會先加載所有實現了這個接口的類,也就是所有插入式注解處理器(包括你自定義的),這實際上破壞了雙親委派模型

在這里插入圖片描述

因為對于javac(對一般的java程序也一樣)來說,這些插入式注解處理的實現(SPI)都屬于“應用程序級”的,應該由最低級的應用程序類加載器加載

但實際上,他們的接口都位于“高層”,其接口是由啟動類加載器加載的,但是這些高層的接口要去加載自己的實現類,就屬于高級類加載器加載低級類加載器了

這里,java引入了線程上下文類加載器,這個加載器可以跨界進行加載,這樣就能幫助高層的加載器加載底層的類

至于這里為什么強調“線程上下文”,我們可以以tomcat舉例:通常里面有多個線程來處理請求,相互應該隔離:對于java,不同類加載器加載的同一個類,視為不同類,不相同也不兼容,這樣就能隔離開不同線程

也不用擔心每個線程都要去加載一個SPI,只會進行一次類加載,剩下的都會從緩存之中直接加載,盡管是其他線程

總而言之

通過SPI,我們就能解決Javac在準備編譯時去加載插入式注解處理器的問題了


解析與填充符號表

詞法語法分析

這里會把代碼中的字符流轉化為標記(Token),Token是編譯時的最小元素,比如int a = b + 2,會拆分成6個Token:int ,a,=,b,+,2

接著會把這些Token按照順序構造成抽象語法樹(AST),其代表了一個程序的語法結構,你可以理解為是一個能保存一個程序的所有信息的數據結構

之后,Javac就不會再操作字符流了,一切都會圍繞著語法樹來進行

填充符號表

符號表類似于一個哈希表,用來標識每一個符號的地址和其信息,用人話來說的話,就是會標記一些Token,記錄下這些Token的名字,類型,作用域等等,譬如方法名,變量名這類的,會用來進行各種檢測,優化:比如語法檢查,分配地址子類的,符號表就像是電話簿一樣的角色


注解處理器處理注解

這里相對的簡單:會調用每一個注解處理器進行處理,如果其對語法樹進行了更改:就會回退到解析與填充符號表 重新處理,因為可能改變了語法以及符號表,這個操作稱之為輪(Round),可以抽象成下面這個圖

在這里插入圖片描述

當所有注解處理器都處理完成后,便會進入下一個階段:


語義分析與生成字節碼

這里已經具有了一個完整的語法樹和符號表,最后一步就是把這些轉化成字節碼了

標注檢查

這里會進行類型賦值是否互相兼容,變量使用前是否聲明,還會進行常量折疊,這是前端編譯中為數不多的優化:int a = 1 + 2,這里會把1 + 2 在語法樹上直接變成3

數據及控制流分析

這里會對各種邏輯進行進一步的驗證,比如,對于局部變量用之前有無賦值,是否有返回值,異常是否會處理這種更復雜的控制

值得注意的是,這里的分析是和類加載期間的分析(運行時)基本相同,但存在一些東西只能在編譯期或者運行時檢測

就比如說局部變量的final,JVM對于字節碼的要求是越短越好,對于局部變量的final關鍵字會直接被消除,那如何保證其值不會變?那就輪到編譯器來判斷了

為什么不會去掉成員變量的final?因為JVM 運行時有可能用到(比如常量折疊、只讀約束等)

解語法糖

語法糖是一些用來幫助程序員進行編程的特殊語法,或許其不嚴謹或不規范但是其能大幅度提升程序員的幸福度

包括泛型(是的,Java匪夷所思沒有真正的實現泛型,詳見類型擦除),自動拆裝箱,自動變長參數等,這些語法會在這個階段被替換成最基礎的語法

字節碼生成

這里是最后一個階段:把語法樹,符號表轉化成字節碼

字節碼的格式極其嚴格,這里會把其嚴格的轉化成字節碼,并向其中添加一些其他的代碼,比如類構造器,實例構造器

變量初始化,調用父類構造等等

并還會添加一些優化,比如把字符串的+替換成StringBuffer的append之類的

到此,編譯結束


現在已經生成了一份詳盡且嚴謹的字節碼,接下來一步就是開始解釋執行,并開始最大的舞臺:后端編譯及優化

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

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

相關文章

JWT6報錯誤 kid empty unable to lookup correct key

JWT5和jwt6在加密和解密和時候還明些區別的 ,在5中,是不需要這個kid的,加解都不需要。但6中是需要這個keyId。 所以在使用的時候要做個區別,參考下面鏈接: ThinkPhp5.0.24 JWT報錯 ‘“kid“ empty, unable to lookup…

高效學習之一篇搞定分布式管理系統Git !

一、Git是什么1.Git是目前世界上最先進的分布式版本管理系統 2.工作原理/流程workspace:工作區 Index/Stage:暫存區 Repository:倉庫區(本地倉庫) Remote:遠程倉庫二、SVN和Git的最主…

AdsPower API 新增查詢環境 Cookies 接口,自動化更進一步!

你是不是有過這樣的經歷?賬號在 AdsPower 環境中已經成功登錄,但你還要花時間手動導出 Cookies、再整理處理,過程繁瑣、效率低下。 現在,我們上線了 API 查詢環境 Cookies 的接口,支持通過 API 直接獲取已登錄環境的 …

Craftium游戲引擎中的客戶端同步機制解析

Craftium游戲引擎中的客戶端同步機制解析 craftium A framework for creating rich, 3D, Minecraft-like single and multi-agent environments for AI research based on Minetest 項目地址: https://gitcode.com/gh_mirrors/cr/craftium 游戲狀態同步的核心問題 在分…

spring cloud負載均衡之FeignBlockingLoadBalancerClient、BlockingLoadBalancerClient

本文主要分析被 FeignClient 注解的接口類請求過程中負載均衡邏輯&#xff0c;流程分析使用的源碼版本信息如下&#xff1a;<spring-boot.version>3.2.1</spring-boot.version><spring-cloud.version>2023.0.0</spring-cloud.version>背景 平常我們代碼…

提示工程(Prompt Engineering)研究進展

提示工程(Prompt Engineering)研究進展 以及它如何幫助大語言模型(LLMs)和視覺語言模型(VLMs)更好地工作。用簡單的話說,就是通過設計巧妙的“提示”(比如指令、例子),讓模型在不修改內部參數的情況下,更精準地完成各種任務,比如回答問題、推理、生成內容等。 文檔…

【ARM】AI開發板A7處理器JTAG實現指南

一、文檔背景盡管開發板原廠提供了相關文檔&#xff0c;但可能缺乏對 A7 處理器 JTAG 功能的詳細說明。這可能會導致以下問題&#xff1a;開發人員難以理解和利用 A7 處理器的基本功能&#xff0c;阻礙調試和開發進度。在進行Uboot移植過程中&#xff0c;無法應用圖形界面的調試…

FPGA(一)Quartus II 13.1及modelsim與modelsim-altera安裝教程及可能遇到的相關問題

零.前言 在學習FPGA課程時&#xff0c;感覺學校機房電腦用起來不是很方便&#xff0c;想著在自己電腦上下載一個Quartus II 來進行 基于 vhdl 語言的FPGA開發。原以為是一件很簡單的事情&#xff0c;沒想到搜了全網文章發現幾乎沒有一個完整且詳細的流程教學安裝&#xff08;也…

軟考(軟件設計師)存儲管理—存儲空間管理,文件共享保護

一、文件存取方法 1. 順序存取&#xff08;Sequential Access&#xff09; 原理&#xff1a;按記錄寫入順序依次訪問特點&#xff1a; 讀操作&#xff1a;讀取當前位置&#xff0c;指針自動前移寫操作&#xff1a;追加到文件末尾 適用場景&#xff1a;磁帶設備、日志文件 #merm…

Thinkphp6中如何將macro方法集成到Request類中

在學習crmeb的時候發現他使用了一個macro的方法用在中間件中&#xff0c;于對macro進行了簡單的研究&#xff0c;發現這個方法可以在中間件中進行定義一些方法&#xff0c;然后讓后面的控制器進行使用。 如&#xff1a; 在授權的中間件中&#xff0c;定義了$request->macro…

Java List 使用詳解:從入門到精通

一、List 基礎概念1.1 什么是 List&#xff1f;List 就像是一個智能書架&#xff1a;可以按順序存放書籍&#xff08;元素&#xff09;每本書都有固定位置&#xff08;索引&#xff09;可以隨時添加、取出或重新排列書籍// 創建一個書架&#xff08;List&#xff09; List<S…

Java零基礎筆記06(數組:一維數組、二維數組)

明確: 程序是用來處理數據的, 因此要掌握數據處理的數據結構數組是編程中常用的數據結構之一&#xff0c;用于存儲一系列相同類型的元素。在Java中&#xff0c;數組是一種對象&#xff0c;可以存儲固定大小的相同類型元素的集合。1.一維數組數組是一個數據容器,可用來存儲一批同…

10倍處理效率提升!阿里云大數據AI平臺發布智能駕駛數據預處理解決方案

阿里云大數據AI平臺重磅發布智能駕駛數據預處理解決方案&#xff0c;可幫助汽車行業客戶實現構建高效、穩定的數據預處理產線流程&#xff0c;數據包處理效率相比自建可提升10倍以上&#xff0c;數據處理推理任務優化提速1倍以上&#xff0c;相同資源產能提升1倍[1]&#xff0c…

SAP HANA內存數據庫解析:特性、優勢與應用場景 | 技術指南

SAP HANA 是一款列式內存關系數據庫&#xff0c;集 OLAP 和 OLTP 操作于一體。相較于同類產品&#xff0c;SAP HANA 需要的磁盤空間更少&#xff0c;并且可擴展性高。SAP HANA 可以部署在本地、公有云或私有云以及混合場景中。該數據庫適用于各種數據類型的高級分析和事務處理。…

Openharmony4.0 rk3566上面rknn的完美調用

一 背景&#xff1a; 我們都知道如果要在android上面使用rknn推理模型需要按照如下的步驟&#xff1a; 詳細請參考筆者的文章&#xff1a;Android11-rk3566平臺上采用NCNN&#xff0c;RKNN框架推理yolo11官方模型的具體步驟以及性能比較-CSDN博客 簡而言之就是 模型轉換&#…

Java多線程知識小結:Synchronized

在Java中&#xff0c;synchronized 關鍵字是實現線程同步的核心工具&#xff0c;用于保證同一時刻只有一個線程可以執行被修飾的代碼塊或方法。以下從基本原理、鎖升級過程、應用場景及優化建議四個維度詳細解析&#xff1a; 一、基本原理 1. 同步的對象 synchronized 鎖的是對…

MTK項目wifi.cfg文件如何配置的Tput和功耗參數

下面的MTK參數主要與無線網絡(Wi-Fi)配置相關,特別是與WMM(Wi-Fi Multimedia)和功率控制相關的設置 WMM相關參數: WmmParamCwMax/WmmParamCwMin:定義競爭窗口的最大/最小值,這里設置為10/4,用于控制信道訪問的退避機制13 WmmParamAifsN:仲裁幀間間隔數,設置為3影響不同…

分水嶺算法:圖像分割的浸水原理

分水嶺算法&#xff1a;基于拓撲地貌的邊界提取核心原理 分水嶺算法將圖像視為拓撲地貌&#xff0c;灰度值代表海拔高度。通過模擬浸水過程&#xff1a;局部極小值&#xff1a;對應集水盆&#xff08;區域內部&#xff09;。分水嶺線&#xff1a;集水盆之間的山脊&#xff08;區…

汽車功能安全系統階段開發【技術安全方案TSC以及安全分析】5

文章目錄1 技術安全方案 (Technical Safety Concept - TSC)2 系統安全架構設計 (System Safety Architecture Design)3 如何進行安全分析 (Safety Analysis)4 技術安全需求 (TSR) 如何分配到系統架構1 技術安全方案 (Technical Safety Concept - TSC) 技術安全方案 (Technical…

學習軟件測試的第十二天(接口測試)

一.如果一個接口請求不通&#xff0c;那么你會考慮那些方面的問題&#xff1f;如果一個接口請求不通&#xff0c;我會像“排查水管漏水”一樣一步步定位問題發生在哪一段&#xff0c;主要從這幾個方向去思考&#xff1a;當一個接口請求不通時&#xff0c;我會從以下幾個方面進行…