Java 字節碼文件(.class)的組成詳解

文章目錄

    • 基礎信息
    • 常量池
    • 字段
    • 方法
    • 屬性
    • 字節碼文件內容說明案例
      • 文件基本信息
      • 類的基本信息
      • 常量池
      • 字段信息
      • 構造方法
      • 實例方法
      • 主方法
      • 源文件信息

字節碼文件由五部分組成,分別是基礎信息、常量池、字段、方法、屬性。

案例:

public class Main implements InterfaceA {public static final String HELLO = "hello";public static final String WORLD = "world";public static final String HELLO2 = "hello";public static final String hello = "hello";public void methodA() {String all = HELLO + WORLD;System.out.println(all);}public static void main(String[] args) {Main main = new Main();main.methodA();}}

以下將以上述內容為案例,說明字節碼文件的五部分內容。

基礎信息

基礎信息中包含魔數、字節碼文件對應的 Java 版本號、訪問標識(publicfinal 等等)及父類和接口。

  • 魔數:魔數用于標識當前文件是 java 語言的字節碼文件(.class),其固定值為 0xCAFEBABE
  • 主/次版本號:主/次版本號確定當前字節碼文件對應的 JDK 版本號,用于判斷當前字節碼文件的版本與運行該字節碼文件的 JDK 的版本是否兼容。其中,主版本號用來標識大版本號,例如 JDK1.0-1.1 使用了 45.0-45.3,JDK1.2 是 46 之后每升級一個大版本就加 1;副版本號是當主版本號相同時作為區分不同版本的標識,一般只需要關心主版本號。

使用 jclasslib 打開 Main.class 查看一般信息:

在這里插入圖片描述

常量池

常量池中保存字符串常量、類或接口名、字段名,這些內容主要在字節碼指令中使用。常量池可以避免內容重復定義,減小 .class 文件的大小,從而達到節省空間的目的。

例如,使用 jclasslib 打開 Main.class 查看常量池中 String 類型的常量發現只有 3 個:

在這里插入圖片描述

打開這 3 個常量信息,發現它們的值分別是 helloworldhelloworld

在這里插入圖片描述

String 類型的常量只有 3 個而不是 5 個的原因是成員變量 HELLOHELLO2hello 都指向常量池中的同一個值 hello

需要注意的是,類實現的接口信息也存放于常量池中:

在這里插入圖片描述

字段

字段中包含當前類或接口聲明的字段信息。

使用 jclasslib 打開 Main.class 可以查看定義了 4 個字段信息:

在這里插入圖片描述

而其中 3 個指向了常量池中的同一個值為 hello 的地址:

在這里插入圖片描述

即上文提到的常量池避免內容重復定義。

方法

方法中包含當前類或接口聲明的方法信息。

使用 jclasslib 打開 Main.class 查看方法信息:

在這里插入圖片描述

屬性

屬性中包含類的屬性,比如源碼的文件名、內部類的列表等。

使用 jclasslib 打開 Main.class 查看屬性信息:

在這里插入圖片描述

字節碼文件內容說明案例

以上述 Main.java 編譯后的字節碼文件 Main.class 為例,通過 javap -v Main.class > Main.class.txt 得到 Main.class.txt

Main.class.txt 內容如下:

Classfile /home/wftapp/test/Main.classLast modified Aug 6, 2025; size 814 bytesMD5 checksum ccde33e85e9b2fe106990c9f5c38f6bcCompiled from "Main.java"
public class Main implements InterfaceAminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #8.#33         // java/lang/Object."<init>":()V#2 = Class              #34            // Main#3 = String             #35            // helloworld#4 = Fieldref           #36.#37        // java/lang/System.out:Ljava/io/PrintStream;#5 = Methodref          #38.#39        // java/io/PrintStream.println:(Ljava/lang/String;)V#6 = Methodref          #2.#33         // Main."<init>":()V#7 = Methodref          #2.#40         // Main.methodA:()V#8 = Class              #41            // java/lang/Object#9 = Class              #42            // InterfaceA#10 = Utf8               HELLO#11 = Utf8               Ljava/lang/String;#12 = Utf8               ConstantValue#13 = String             #17            // hello#14 = Utf8               WORLD#15 = String             #43            // world#16 = Utf8               HELLO2#17 = Utf8               hello#18 = Utf8               <init>#19 = Utf8               ()V#20 = Utf8               Code#21 = Utf8               LineNumberTable#22 = Utf8               LocalVariableTable#23 = Utf8               this#24 = Utf8               LMain;#25 = Utf8               methodA#26 = Utf8               all#27 = Utf8               main#28 = Utf8               ([Ljava/lang/String;)V#29 = Utf8               args#30 = Utf8               [Ljava/lang/String;#31 = Utf8               SourceFile#32 = Utf8               Main.java#33 = NameAndType        #18:#19        // "<init>":()V#34 = Utf8               Main#35 = Utf8               helloworld#36 = Class              #44            // java/lang/System#37 = NameAndType        #45:#46        // out:Ljava/io/PrintStream;#38 = Class              #47            // java/io/PrintStream#39 = NameAndType        #48:#49        // println:(Ljava/lang/String;)V#40 = NameAndType        #25:#19        // methodA:()V#41 = Utf8               java/lang/Object#42 = Utf8               InterfaceA#43 = Utf8               world#44 = Utf8               java/lang/System#45 = Utf8               out#46 = Utf8               Ljava/io/PrintStream;#47 = Utf8               java/io/PrintStream#48 = Utf8               println#49 = Utf8               (Ljava/lang/String;)V
{public static final java.lang.String HELLO;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic static final java.lang.String WORLD;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String worldpublic static final java.lang.String HELLO2;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic static final java.lang.String hello;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic Main();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   LMain;public void methodA();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=10: ldc           #3                  // String helloworld2: astore_13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;6: aload_17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V10: returnLineNumberTable:line 12: 0line 13: 3line 14: 10LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   LMain;3       8     1   all   Ljava/lang/String;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #2                  // class Main3: dup4: invokespecial #6                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #7                  // Method methodA:()V12: returnLineNumberTable:line 17: 0line 18: 8line 19: 12LocalVariableTable:Start  Length  Slot  Name   Signature0      13     0  args   [Ljava/lang/String;8       5     1  main   LMain;
}
SourceFile: "Main.java"

Main.class.txt 的各個組成部分的詳細解釋如下。

文件基本信息

Classfile /home/wftapp/test/Main.classLast modified Aug 6, 2025; size 814 bytesMD5 checksum ccde33e85e9b2fe106990c9f5c38f6bcCompiled from "Main.java"
  • Classfile:指定了字節碼文件的路徑。
  • Last modified:文件的最后修改時間。
  • size:文件的大小,單位是字節。
  • MD5 checksum:文件的 MD5 校驗和,用于驗證文件的完整性。
  • Compiled from:該字節碼文件是由哪個 Java 源文件編譯而來的。

類的基本信息

public class Main implements InterfaceAminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
  • public class Main implements InterfaceA:聲明了一個公共類 Main,該類實現了接口 InterfaceA
  • minor version:次要版本號,這里是 0。
  • major version:主要版本號,52 對應 Java 8。
  • flags:類的訪問標志,ACC_PUBLIC 表示該類是公共的,ACC_SUPER 是一個歷史遺留標志,現代 Java 編譯器都會設置這個標志。

常量池

Constant pool:#1 = Methodref          #8.#33         // java/lang/Object."<init>":()V#2 = Class              #34            // Main#3 = String             #35            // helloworld...

常量池是字節碼文件的重要組成部分,它包含了類、方法、字段等的符號引用和字面量。每個常量都有一個唯一的索引,通過這些索引可以在字節碼中引用常量。例如,#1 是一個方法引用,指向 java/lang/Object 類的構造方法。

字段信息

{public static final java.lang.String HELLO;descriptor: Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String hellopublic static final java.lang.String WORLD;...

聲明了幾個公共靜態常量字段,如 HELLOWORLD 等。

  • descriptor:字段的類型描述符,Ljava/lang/String; 表示該字段是 String 類型。
  • flags:字段的訪問標志,ACC_PUBLIC 表示公共的,ACC_STATIC 表示靜態的,ACC_FINAL 表示常量。
  • ConstantValue:常量字段的值,這里 HELLO 的值是 "hello"

構造方法

  public Main();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   LMain;
  • public Main():公共的無參構造方法。
  • descriptor:方法的描述符,()V 表示該方法沒有參數,返回值為 void
  • flags:方法的訪問標志,ACC_PUBLIC 表示公共的。
  • Code:方法的字節碼指令,這里調用了父類 Object 的構造方法。
  • LineNumberTable:行號表,用于將字節碼指令與源文件的行號對應起來。
  • LocalVariableTable:局部變量表,記錄了方法中局部變量的信息,這里 thisMain 類的實例。

實例方法

  public void methodA();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=10: ldc           #3                  // String helloworld2: astore_13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;6: aload_17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V10: returnLineNumberTable:line 12: 0line 13: 3line 14: 10LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   LMain;3       8     1   all   Ljava/lang/String;
  • public void methodA():公共的實例方法,沒有參數,返回值為 void
  • Code:方法的字節碼指令,這里將字符串 "helloworld" 壓入棧,然后調用 System.out.println 方法打印該字符串。
  • LineNumberTable:行號表,將字節碼指令與源文件的行號對應。
  • LocalVariableTable:局部變量表,記錄了方法中局部變量的信息,thisMain 類的實例,all 是存儲 "helloworld" 的局部變量。

主方法

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #2                  // class Main3: dup4: invokespecial #6                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #7                  // Method methodA:()V12: returnLineNumberTable:line 17: 0line 18: 8line 19: 12LocalVariableTable:Start  Length  Slot  Name   Signature0      13     0  args   [Ljava/lang/String;8       5     1  main   LMain;
  • public static void main(java.lang.String[]):Java 程序的入口方法。
  • Code:方法的字節碼指令,這里創建了一個 Main 類的實例,然后調用該實例的 methodA 方法。
  • LineNumberTable:行號表,將字節碼指令與源文件的行號對應。
  • LocalVariableTable:局部變量表,記錄了方法中局部變量的信息,args 是命令行參數數組,mainMain 類的實例。

源文件信息

SourceFile: "Main.java"

指定了該字節碼文件對應的源文件名稱。

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

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

相關文章

C++之vector類的代碼及其邏輯詳解 (下)

1. insert()這個就是在指定位置插入一個元素&#xff0c;首先計算要插入的這個位置和開頭之間的距離&#xff0c;接著判斷那個_finish 有沒有碰到_endofstorage 或者_endofstorage 是不是為0&#xff0c;如果滿足條件&#xff0c;那就進行擴容&#xff0c;然后接著重新計算距離…

【自動化測試】Python Selenium 自動化測試元素定位專業教程

1. 引言&#xff1a;元素定位在 Selenium 中的核心地位 元素定位是 Selenium 自動化測試的基礎&#xff0c;所有用戶交互操作&#xff08;如點擊、輸入、選擇&#xff09;都依賴于準確識別頁面元素。Selenium WebDriver 提供了多種定位策略&#xff0c;從簡單的 ID 定位到復雜…

通用代碼自用

多文件上傳public int save(Role role, RequestParam("nfile") MultipartFile nfile, HttpServletRequest request) {System.out.println(nfile.getOriginalFilename());String path request.getSession().getServletContext().getRealPath("/upload");Fi…

生成式AI如何顛覆我們的工作和生活

原問題&#xff1a; ?你覺得生成式AI未來會如何改變普通人的工作和生活&#xff1f;? 做過一個對比國外和國內工業化產品制造的簡單調研&#xff0c;類似一款定制化的臺燈或者語音音響&#xff0c;從零到原型實物&#xff0c; 美國至少需要20萬美刀&#xff0c;國內成本大概…

K8S、Docker安全漏洞靶場

1 介紹 一個脆弱基礎設施自動化構建框架,主要用于快速、自動化搭建從簡單到復雜的脆弱云原生靶機環境。 1.1 項目的緣起 在研究漏洞時,我們經常會發現“環境搭建”這一步驟本身就會占用大量的時間,與之相比,真正測試PoC、ExP的時間可能非常短。由于許多官方鏡像在國內的…

使用Nginx部署前后端分離項目

使用Nginx部署前后端分離項目&#xff1a;用戶中心系統實踐指南 部署前的關鍵準備 在正式部署前&#xff0c;務必確保前后端在生產環境能正常運行&#xff1a; 前端&#xff1a;測試所有API請求路徑和生產環境配置后端&#xff1a;驗證數據庫連接、環境變量和外部服務集成完整流…

當前就業形勢下,軟件測試工程師職業發展與自我提升的必要性

軟件測試行業正處于深刻變革期&#xff0c;2025年的市場已超越400億美元規模&#xff0c;預計2027年將增長7% 。在這個技術驅動、效率至上的時代&#xff0c;測試工程師若想保持競爭力&#xff0c;必須主動擁抱變革&#xff0c;系統性提升技能。通過深入分析行業現狀與人才需求…

java 之 繼承

一、繼承 1.1 、什么是繼承&#xff1f; 繼承就是把所有的類的公共部分&#xff08;相同的成員&#xff09;提取出來&#xff0c;放到一個類中繼承需要使用 extends 關鍵字 public class Animal{ public String name&#xff1b; } public class Dog extends Animal{}Dog 是 An…

強化應急通信生命線:遨游三防平板、衛星電話破局極端災害救援

暴雨傾盆&#xff0c;山洪咆哮&#xff0c;城市陷入內澇。今年進入汛期以來&#xff0c;我國廣東、福建、河南、陜西、京津冀等地相繼遭遇暴雨、洪澇、山洪等災害&#xff0c;道路損毀、基站斷網、電力中斷等次生問題為應急響應帶來嚴峻挑戰。如何保障極端場景下的通信暢通&…

【Linux系統】進程間通信:命名管道

1. 匿名管道的限制匿名管道存在以下核心限制&#xff1a;僅限親緣關系進程&#xff1a;只能用于父子進程等有血緣關系的進程間通信&#xff08;如通過 fork() 創建的子進程&#xff09;。單向通信&#xff1a;數據只能單向流動&#xff08;一端寫&#xff0c;另一端讀&#xff…

Python Day24 多線程編程:核心機制、同步方法與實踐案例

一、線程事件對象&#xff08;threading.Event&#xff09;threading.Event 用于實現線程間的通信&#xff0c;可讓一個線程通知其他線程終止任務&#xff0c;核心是通過 “事件觸發” 機制協調線程行為。核心方法&#xff1a;創建事件對象&#xff1a;event threading.Event(…

007 前端( JavaScript HTML DOM+Echarts)

一.html dom運用查找html元素的三種方式通過 id 找到 HTML 元素通過標簽名找到 HTML 元素通過類名找到 HTML 元素1.通過 id 找到 HTML 元素<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>msf的網頁</title> <…

實習文檔背誦

實習內容:1.定時任務與數據補全:基于 XXL-JOB 實現分布式定時任務調度&#xff0c;補全近半年歷史操作日志數據&#xff0c;有效解決因網絡異常導致的數據缺失問題。業務場景&#xff1b;集團的4a日志半年內沒有同步&#xff0c;這邊需要把日志數據同步到集團上首先先評估每天的…

分布式CAP定理

CAP 定理在一個分布式系統中&#xff0c;以下三個特性不可能同時完全滿足&#xff0c;最多只能滿足其中兩個&#xff1a;C&#xff08;Consistency&#xff0c;一致性&#xff09;&#xff1a;所有節點在同一時間看到的數據是完全一致的&#xff08;即更新操作成功并返回后&…

PHP-Casbin:現代化 PHP 應用的權限管理引擎

在當今復雜的Web應用中&#xff0c;精細化的權限管理是保障系統安全的關鍵環節。PHP-Casbin 作為Casbin生態的PHP實現&#xff0c;憑借其靈活的模型支持和強大的擴展能力&#xff0c;已成為PHP開發者實現訪問控制的首選工具。 超越傳統權限模型 PHP-Casbin 基于PERM&#xff…

FastDeploy2.0:環境變量的說明

一、執行# 設置日志目錄 export FD_LOG_DIR/workspace/models/log# 指定使用的 GPU 設備 export CUDA_VISIBLE_DEVICES0,1,2,3# 創建日志目錄&#xff08;如果不存在&#xff09; mkdir -p "$FD_LOG_DIR"# 定義日志文件路徑 LOG_FILE"$FD_LOG_DIR/fastdeploy_se…

C語言:指針(1-2)

5. 指針運算指針的基本運算有三種&#xff0c;分別是&#xff1a;指針-整數指針-指針指針的關系運算5.1 指針運算在上面&#xff0c;我們知道&#xff0c;數組在內存中是連續存放的&#xff0c;只要知道第一個元素的地址&#xff0c;順藤摸瓜就能找到后面的所有元素。那么&…

【多模態】DPO學習筆記

DPO學習筆記1 原理1.0 名詞1.1 preference model1.2 RLHF1.3 從RLHF到DPOA.解的最優形式B. DPO下參數估計C. DPO下梯度更新D. DPO訓練的穩定性2 源代碼2.1 數據集構成2.2 計算log prob2.3 DPO loss1 原理 1.0 名詞 preference model&#xff1a;對人類偏好進行建模&#xff0…

2025最新、UI媲美豆包、DeepSeek等AI大廠的AIGC系統 - IMYAI源碼部署教程

IMYAI 系統部署與使用手冊 一、系統演示 &#x1f539; 快速體驗 前端演示地址&#xff1a;https://super.imyaigc.com后臺演示地址&#xff1a;https://super.imyaigc.com/settings &#x1f539; 技術架構 前端&#xff1a;Vite Vue3 NaiveUI TailwindCSS Plyr后端&…

【關于Java的反射】

在 Java 編程中&#xff0c;反射&#xff08;Reflection&#xff09; 是一個非常強大的工具&#xff0c;它允許你在運行時動態地獲取類的信息、創建對象、調用方法和訪問字段。雖然反射功能強大&#xff0c;但它也有一些局限性和性能開銷&#xff0c;因此需要謹慎使用。一、什么…