jvm中類和對象定義存儲基礎知識

来源:https://www.cnblogs.com/jingdongkeji/archive/2023/06/07/17463760.html
-Advertisement-
Play Games

在Java虛擬機中,類和對象是程式的基本組成單元。類定義了一組對象的共性特征和行為,是Java程式中最基本的代碼單元。而對象則是具體的實例,有自己獨特的狀態和行為。在JVM中,類和對象都需要進行存儲,因此瞭解類和對象的存儲基礎知識對於Java程式員來說是非常重要的。 ...


1 類文件數據結構類型

Class文件結構主要有兩種數據結構:無符號數和表

無符號數:用來表述數字,索引引用、數量值以及字元串等,比如 圖1中類型為u1,u2,u4,u8分別代表1個位元組,2個位元組,4個位元組,8個位元組的無符號數

:表是有由多個無符號數以及其它的表組成的複合結構,比如圖1中類型以_info結尾的項為表類型。

2 類結構定義

Class類文件是緊湊、順序、無空隙的,魔數(MagicNumber)、Class文件版本(Version)、常量池(Constant_Pool)、訪問標記(Access_flag)、本類(This_class)、父類(Super_class)、介面(Interfaces)、欄位集合(Fields)、方法集合(Methods )、屬性集合(Attributes)。其中因為java多繼承所以interfaces介面類型為數組;attribute_info則是方法表中定義的code索引,指向具體的方法體位元組碼。如圖1所示。

下麵用一段程式做說明,此類有介面,有方法、類變數和實例變數,機器是如何識別位元組碼然後按照上面的規則來定義此class類呢?

package com.jd.crm.Logback;

public class TestClass implements Super{

    private static final int staticVar = 0;

    private int instanceVar=0;

    public int instanceMethod(int param) throws  Exception{
        return param ++;
    }
}
interface Super{ }

通過javap幫助解析class文件格式如下:

Classfile /D:/spm-workspace/test/target/classes/com/jd/crm/Logback/TestClass.class
  Last modified 2023-4-14; size 597 bytes
  MD5 checksum 9d5dd9fc2145ac17393fee7a707d3b9c
  Compiled from "TestClass.java"
public class com.jd.crm.Logback.TestClass implements com.jd.crm.Logback.Super
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#26         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#27         // com/jd/crm/Logback/TestClass.instanceVar:I
   #3 = Class              #28            // com/jd/crm/Logback/TestClass
   #4 = Class              #29            // java/lang/Object
   #5 = Class              #30            // com/jd/crm/Logback/Super
   #6 = Utf8               staticVar
   #7 = Utf8               I
   #8 = Utf8               ConstantValue
   #9 = Integer            0
  #10 = Utf8               instanceVar
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/jd/crm/Logback/TestClass;
  #18 = Utf8               instanceMethod
  #19 = Utf8               (I)I
  #20 = Utf8               param
  #21 = Utf8               Exceptions
  #22 = Class              #31            // java/lang/Exception
  #23 = Utf8               MethodParameters
  #24 = Utf8               SourceFile
  #25 = Utf8               TestClass.java
  #26 = NameAndType        #11:#12        // "<init>":()V
  #27 = NameAndType        #10:#7         // instanceVar:I
  #28 = Utf8               com/jd/crm/Logback/TestClass
  #29 = Utf8               java/lang/Object
  #30 = Utf8               com/jd/crm/Logback/Super
  #31 = Utf8               java/lang/Exception
{
  public com.jd.crm.Logback.TestClass();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_0
         6: putfield      #2                  // Field instanceVar:I
         9: return
      LineNumberTable:
        line 3: 0
        line 7: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/jd/crm/Logback/TestClass;

  public int instanceMethod(int) throws java.lang.Exception;
    descriptor: (I)I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: iload_1
         1: iinc          1, 1
         4: ireturn
      LineNumberTable:
        line 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/jd/crm/Logback/TestClass;
            0       5     1 param   I
    Exceptions:
      throws java.lang.Exception
    MethodParameters:
      Name                           Flags
      param
}
SourceFile: "TestClass.java"

以上是javap幫助我們生成的class文件解析結果,只是給人看,而非機器。

通過編譯後生成class文件格式如下,因為class文件是以8位作為一個位元組的二進位流。為了方便計算,用16進位表示二進位(1個位元組=2個十六進位的數,故下麵每2個數就代表1個位元組)

2.1 魔法數

前四個位元組cafebabe是固定值,任何語言編譯成jvm認識的二進位流,前四位必須是固定的cafebabe位元組。

2.2 版本號

緊接著2個位元組00表示次版本號為0 ;0034代表主版本為52(jdk版本號對應的jdk版本為1.8)參考jdk版本和class位元組版本的對應關係

2.3 常量個數

常量個數const_pool_count位元組碼為00 20對應的說明常量個數為32,實際為31個,因為首位jvm作為保留位使用。

2.4 常量池

常量池存放兩大常量:字面量和符號引,字面量如文本字元串,被生命的final常量值等,而符號引用則包含類、介面的全限名稱、欄位、方法名稱和描述符號等等。參考javap生成的類文件信息。

這裡只分析下其中一個常量,在上面常量個數2個位元組後面緊接著一個位元組0a十進位為10,參考常量池類型10代表類中方法的符號引用。繼續參考方法類型MethodRef_info個格式定義:前兩個位元組0004代表方法所在類名稱的索引,後兩個位元組0001a代表一個NameAndType類型的索引。

2.5 類訪問標誌

緊接常量池定義完後的u2標識訪問標誌,本例標識為0x0021和下圖標誌位按位或計算,如0x0001為真,0x0020也為真,其他為否 最終確認訪問標誌位ACC_PUBLIC、ACC_SUPER

2.6 本類、父類、介面索引集合

根據圖1的規則,u2兩個位元組0003標識當前類名的引用到,引用常量池數組下標為#3,根據圖3所示子項的類名為com/jd/crm/Logback/TestClass;0004代表父類類名的引用常量池數組下標為#4,根據圖4所示引用的父類類名為java/lang/Object;緊接著0001標識介面個數,指明數量為1,0005標識第一個介面數組中介面的名稱,指向常量池中下標為5的名稱為com/jd/crm/Logback/Super;

比如查找當前類索引如下圖

2.7 欄位表集合

欄位表以數組的形式定義存儲在常量表中

以上圖說明,0002標識域個數為2個域標識,在本類中有兩個,一個類的域欄位staticVar 一個是實例對象的域欄位instanceVar,如欄位結構定義(下圖)定義,前2個位元組001a為訪問標識,和類訪問標識一樣,分別用001a的二進位和下圖欄位域訪問標識類型做位或運算,得出訪問類型為ACC_PRIVATE類型。name_index的占用兩個位元組0006,指向常量表下標為6的引用,descriptor_index=0007指向常量表下標為7的引用,此處為I標識為數據類型為int,attributes_count=0001為1個,值為0008指向常量表下標為#8的引用常量ConstantValue,標識為靜態變數,最終依次類推第二個域標識引用

欄位結構定義

欄位域的訪問標誌請參考類訪問標誌,邏輯計算一致,只是規則不一樣而已 如下圖

2.8 方法表集合

和域欄位集合表定義類似 也是數組方式定義在常量池中 ,其中方法的結構體第四個欄位attributes_count代表方法的屬性數量,attribute_info就是屬性的集合參考屬性表集合

方法表訪問標識類型

通過上面方法的訪問標誌、名稱索引和描述索引定義方法的基本信息,方法的代碼塊則存放於類型為Code的屬性表中。

2.9 屬性表集合

類、欄位表、方法表本身可包含屬性表,屬性表格結構體如下,屬性表結構類型較多,比如有Code類型、Exception類型、MethodParameters類型等等,具體參考屬性表類型。所有的屬性都是引用常量池中的屬性類型名稱。然後根據屬性的長度指定該屬性的內容,根據屬性的不同類型解析不同的屬性值。格式定義如下

以Code屬性舉例,Code屬性結構如下所示

jvm按屬性獲取attribute_name_index指向常量池一個字元串常量Code,緊接著attribute_length標識Code類型Info信息長度,這個info內容包括:max_stack 最大棧深,max_locals局部變數槽數量,code_length標識機器位元組碼長度,往後查詢位元組碼如下圖所示,其實就是0/1/4/5/6/9的指令集。Code類型又嵌套異常屬性表、行號表LineNumberTable、LocaVariableTable 局部變數表等等信息。如下圖javap生成的類定義信息

1.Code1方法執行過程:

構造方法:descriptor ()V標識無參無返回值為Void的方法索引,flags可見性修飾符;

程式運行時,先將常量池、方法位元組碼、字元串常量池,靜態變數載入到元數據區(1.8後字元串常量池,靜態變數放入了堆);main線程開始運行,分配棧幀記憶體,其中操作數棧stack=2表示運行該方法所需要的最大操作數棧的深度是2;locals=1表示該運行方法所需要的最大局部方法表的最大slot數據是1;args_size是該方法的形參個數,如果是實例方法 第一個形參是this引用。此例正是this引用。所以args_size=1+實際的參數

aload_0: 載入 slot0的局部變數,即this,作為下麵的invokespecial 構造方法調用的參數

invokespecial: 調用構造方法,常量池第#1項,即【Method java/lang/Object.""

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在數據結構中,我們已經學習到了簡單的靜態鏈表以及單鏈表和雙鏈表,它們各有優缺點,但是有個共同的問題是他們呢無法存儲不同的數據。下麵提供了一種方法,可以將不同節點的數據鏈接起來。 下麵的代碼都是基礎的C語言代碼,涉及到的知識點基本覆蓋到C語言學習的所有知識面,尤其是使用了巨集,減少了重覆的代碼。 無論是 ...
  • # 引入 在使用SpringBoot開發時,最常用的註解有@Component、@Service、@Controller、@Configuration等。當類使用這些註解標記時,類會被Spring IOC容器管理,包括創建,填充屬性和實例化。 但是Spring容器如何發現並將這些類放到容器進行管理呢 ...
  • ​ GDAL(Geospatial Data Abstraction Library)是一個在X/MIT許可協議下的開源柵格空間數據轉換庫。它利用抽象數據模型來表達所支持的各種文件格式。它還有一系列命令行工具來進行數據轉換和處理。 Python的GDAL庫作為柵格數據的處理轉換庫,其支持幾百種柵格數 ...
  • ## 前言 在C語言中,巨集定義是一種預處理指令,用於在代碼中定義和使用常量、函數或代碼片段的替代。 巨集定義使用`#define`關鍵字來定義,併在代碼中進行替換。巨集定義具有以下優點: 1. **簡化代碼**:巨集定義可以將一些常用的、重覆出現的代碼片段簡化為一個巨集名稱,提高代碼的可讀性和簡潔性。 2. ...
  • # 列印流 PrintStream 和 PrintWriter ![](https://img2023.cnblogs.com/blog/3008601/202306/3008601-20230604103522664-997405676.png) ![](https://img2023.cnblo ...
  • 操作工作簿 01 新建一個excel工作簿 #2023-4-17 import xlwings as xw # 啟動 excel,但不新建工作簿 app是什麼,app是excel程式本身 app = xw.App(visible=True,add_book=True) #新建一個工作簿 workbo ...
  • # Python 列表推導式:簡潔、高效的數據操作藝術 Python 的列表推導式,這個看似簡單的語法糖,實則內含無限威力。在 Python 代碼編寫中,列表推導式的靈活性和簡潔性讓它成為了不可或缺的一部分。在這篇文章中,我們將更全面、更深入地探討列表推導式,從基礎的概念認識,到各類進階的用法和操作 ...
  • 還記得在2019年的夏天曾經用 R 爬過一份廣州在 lianjia.com 放盤數據 ([博客1](https://www.cnblogs.com/yukiwu/p/10975337.html),[博客2](https://www.cnblogs.com/yukiwu/p/11271515.html ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...