導航:首頁 > 版本升級 > 位元組碼文件該如何理解

位元組碼文件該如何理解

發布時間:2023-01-30 19:34:14

『壹』 java編程中source code和bytecode有什麼區別,不要太詳細的

1、表達不同

代碼是源代碼。位元組碼稱為位元組碼。它是源程序文件生成的類文件,在通過Java編譯器後使用擴展名java生成。它的擴展是類。

2、角色是不同的

位元組碼是包含可執行程序的二進制文件,該可執行程序由一系列操作碼/數據對組成。位元組碼是一種中間代碼,它比機器代碼更抽象,需要翻譯器轉換成機器代碼的中間代碼。無論硬體環境如何,位元組碼主要用於實現特定的軟體操作和軟體環境。位元組碼的實現是通過編譯器和虛擬機實現的。

這是我們根據Java語言規范編寫的源程序文件,擴展名為java。


3、用法不同

位元組碼是中間狀態(中間代碼)的二進制代碼(文件)。您需要將解釋器轉換為機器代碼。寫入運行操作(WORA)實際上是由位元組碼實現的。

通常它已經編譯,但它與特定的機器代碼無關。位元組碼通常不像源代碼那樣可讀,而是一系列編碼數字常量,引用,指令等。

『貳』 什麼是Java位元組碼

它是程序的一種低級表示,可以運行於Java虛擬機上。將程序抽象成位元組碼可以保證Java程序在各種設備上的運行
Java號稱是一門「一次編譯到處運行」的語言,從我們寫的java文件到通過編譯器編譯成java位元組碼文件(.class文件),這個過程是java編譯過程;而我們的java虛擬機執行的就是位元組碼文件。不論該位元組碼文件來自何方,由哪種編譯器編譯,甚至是手寫位元組碼文件,只要符合java虛擬機的規范,那麼它就能夠執行該位元組碼文件。

JAVA程序的運行

因為Java具有跨平台特性,為了實現這個特性Java執行在一台虛擬機上,這台虛擬機也就是JVM,Java通過JVM屏蔽了不同平台之間的差異,從而做到一次編譯到處執行。JVM位於Java編譯器和OS平台之間,Java編譯器只需面向JVM,生成JVM能理解的代碼,這個代碼即位元組碼,JVM再將位元組碼翻譯成真實機器所能理解的二進制機器碼。
位元組碼是怎麼產生的?

我們所編寫的程序都是.java格式,通常在執行的時候也許點擊一下eclipse的運行鍵就可以在控制台看到運行結果,但是也可以更酷一些,如果你裝了JDK,那就可以直接在以命令行的方式編譯運行你的.java文件,編譯後會形成.class文件,這個.class文件即位元組碼。
位元組碼怎麼解讀?

上圖是編譯好的位元組碼文件,即一堆16進制的位元組,如果使用IDE去打開,也許看到的是已經被反編譯的我們所熟悉的java代碼,但這才是純正的位元組碼

這里只介紹位元組碼由哪些部分組成, 具體的意思自行網路或者看文尾的連接, 有較為詳細的講解

上圖即位元組碼文件的組成部分, Class文件的結構不像XML等描述語言那樣鬆散自由。由於它沒有任何分隔符號,

所以,以上數據項無論是順序還是數量都是被嚴格限定的。哪個位元組代表什麼含義,長度是多少,先後順序如何,都不允許改變, 如上圖左側即每一部分規定的長度
魔數(Magic Number)

魔數是用來區分文件類型的一種標志,一般都是用文件的前幾個位元組來表示。
比如0XCAFE BABE表示的是class文件,那麼有人會問,文件類型可以通過文件名後綴來判斷啊?是的,但是文件名是可以修改的(包括後綴),那麼為了保證文件的安全性,將文件類型寫在文件內部來保證不被篡改。
至於為什麼是CAFE BABE估計大家也能猜到, 程序員與咖啡的不解之緣
版本號(Version)
版本號含主版本號和次版本號,都是各佔2個位元組。在此Demo種為0X0000 0033。其中前面的0000是次版本號,後面的0033是主版本號。通過進制轉換得到的是次版本號為0,主版本號為51。高版本的JDK能向下兼容以前版本的Class文件,但不能運行以後版本的Class文件,即使文件格式未發生任何變化. 這就是target參數的用處,可以在使用JDK 1.7編譯時指定-target 1.5
常量池(Constant Pool)
常量池是Class文件中的資源倉庫, 量池中主要存儲2大類常量:字面量和符號引用。字面量如文本字元串,java中聲明為final的常量值等等,而符號引用如類和介面的全局限定名,欄位的名稱和描述符,方法的名稱和描述符。常量池是一個表結構,在表的內容前有一個類型的計數器,表示常量池的長度
上面的表中描述了11中數據類型的結構,其實在jdk1.7之後又增加了3種(CONSTANT_MethodHandle_info,CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)。這樣算起來一共是14種
訪問標志(Access_Flag)
訪問標志信息包括該Class文件是類還是介面,是否被定義成public,是否是abstract,如果是類,是否被聲明成final。通過上面的源代碼,我們知道該文件是類並且是public。
0x 00 21:是0×0020和0×0001的並集。其中0×0020這個標志值涉及到位元組碼指令

類索引(This Class Name)
類索引用於確定類的全限定名
0×00 03 表示引用第3個常量,同時第3個常量引用第19個常量,查找得」com/demo/Demo」。#3.#19
父類索引(Super Class Name)
0×00 04 同理:#4.#20(java/lang/Object)
介面索引(Interfaces)
通過上邊位元組碼圖可以看到,這個介面有2+n個位元組,前兩個位元組表示的是介面數量,後面跟著就是介面的表。我們這個類沒有任何介面,所以應該是0000。果不其然,查找位元組碼文件得到的就是0000。
欄位表集合(fields)
欄位表用於描述類和介面中聲明的變數。這里的欄位包含了類級別變數以及實例變數,但是不包括方法內部聲明的局部變數。接下來就是2+n個欄位屬性。我們只有一個屬性a,所以應該是0001。查找文件果不其然是0001。
該區域含有欄位的訪問標志, 訪問許可權, 欄位的名稱索引, 欄位的描述符索引, 屬性表
描述符的作用就是用來描述欄位的數據類型、方法的參數列表和返回值。而屬性表就是為欄位表和方法表提供額外信息的表結構。對於欄位來說,此處如果將欄位聲明為一個static final msg = "aaa"的常量,則欄位後就會跟著一個屬性表,其中存在一項名為ConstantValue,指向常量池中的一個常量,值為的"aaa"。
方法(methods)
包含訪問標志表, 方法名索引 , 方法描述符索引, 屬性表數量,等
Attribute
0×0001 :同樣的,表示有1個Attributes了。
0x000f : #15(「SourceFile」)
0×0000 0002 attribute_length=2
0×0010 : sourcefile_index = #16(「Demo.java」)
SourceFile屬性用來記錄生成該Class文件的源碼文件名稱。

『叄』 Hermes源碼分析(二)——解析位元組碼

前面一節 講到位元組碼序列化為二進制是有固定的格式的,這里我們分析一下源碼裡面是怎麼處理的

這里可以看到首先寫入的是魔數,他的值為

對應的二進制見下圖,注意是小端位元組序

第二項是位元組碼的版本,筆者的版本是74,也即 上圖中的4a00 0000
第三項是源碼的hash,這里採用的是SHA1演算法,生成的哈希值是160位,因此佔用了20個位元組

第四項是文件長度,這個欄位是32位的,也就是下圖中的為0aa030,轉換成十進制就是696368,實際文件大小也是這么多

後面的欄位類似,就不一一分析了,頭部所有欄位的類型都可以在 BytecodeFileHeader.h 中看到,Hermes按照既定的內存布局把欄位寫入後再序列化,就得到了我們看到的位元組碼文件。

這里寫入的數據很多,以函數頭的寫入為例,我們調用了visitFunctionHeader方法,並通過byteCodeMole拿到函數的簽名,將其寫入函數表(存疑,在實際的文件中並沒有看到這一部分)。注意這些數據必須按順序寫入,因為讀出的時候也是按對應順序來的。

我們知道react-native 在載入位元組碼的時候需要調用hermes的prepareJavaScript方法, 那這個方法做了些什麼事呢?

這里做了兩件事情:
1. 判斷是否是位元組碼,如果是則調用createBCProviderFromBuffer,否則調用createBCProviderFromSrc,我們這里只關注createBCProviderFromBuffer
2.通過BCProviderFromBuffer的構造方法得到文件頭和函數頭的信息(populateFromBuffer方法),下面是這個方法的實現。

BytecodeFileFields的populateFromBuffer方法也是一個模版方法,注意這里調用populateFromBuffer方法的是一個 ConstBytecodeFileFields對象,他代表的是不可變的位元組碼欄位。

細心的讀者會發現這里也有visitFunctionHeaders方法, 這里主要為了復用visitBytecodeSegmentsInOrder的邏輯,把populator當作一個visitor來按順序讀取buffer的內容,並提前載入到BytecodeFileFields裡面,以減少後面執行位元組碼時解析的時間。

Hermes引擎在讀取了位元組碼之後會通過解析BytecodeFileHeader這個結構體中的欄位來獲取一些關鍵信息,例如bundle是否是位元組碼格式,是否包含了函數,位元組碼的版本是否匹配等。注意這里我們只是解析了頭部,沒有解析整個位元組碼,後面執行位元組碼時才會解析剩餘的部分。

evaluatePreparedJavaScript這個方法,主要是調用了HermesRuntime的 runBytecode方法,這里hermesPrep時上一步解析頭部時獲取的BCProviderFromBuffer實例。

runBytecode這個方法比較長,主要做了幾件事情:

這里說明一下,Domain是用於垃圾回收的運行時模塊的代理, Domain被創建時是空的,並跟隨著運行時模塊進行傳播, 在運行時模塊的整個生命周期內都一直存在。在某個Domain下創建的所有函數都會保持著對這個Domain的強引用。當Domain被回收的時候,這個Domain下的所有函數都不能使用。

未完待續。。。

『肆』 位元組碼文件

    .java源文件經過編譯生成的.class便是位元組碼文件,但還不能被系統直接執行,通過JVM解釋翻譯後才可以被底層系統執行。

    1.魔數:頭四個位元組,CAFEBABE

    2.文件版本:java版本1.8 = 52,1.7 = 51……

    3.常量池:包含兩部分 -- 字面量與符號引用

        ① 字面量:字元串文本、用final修飾的基本數據類型的值。(如申明的:String s = "abc";中的"abc",int i = 1;中的1)。大白話:字面量是在編譯期間就已有確定值的數據。

        ② 符號引用:類、介面、方法、欄位的全名與描述符。在編譯時,java類並不知道引用類的實際內存地址,因此只能使用符號引用來代替。在類載入器鏈接階段時才替換為具體的實際內存地址,即直接引用。

    4.訪問標志:(類、屬性、方法)的訪問標志

        是class還是interface,是否public,是否abstract,是否定義了final等等。

    5.類/父類索引與介面索引集合

        類、父類、介面集合的全限定名。

    6.欄位表集合

        聲明的類變數與實例變數的描述與結構。

    7.方法表集合

        聲明的方法的描述與結構。

    8.屬性表集合

        描述class文件,欄位表,方法表某些場景專有的信息。

『伍』 Java中位元組碼文件怎麼理解由解釋器執行,由瀏覽器執行

「java解釋器就是把在java虛擬機上運行的目標代碼(位元組碼)解釋成為具體平台的版機器碼的程序。」即jdk或權jre目錄下bin目錄中的java.exe文件,而javac.exe是編譯器。
運行java程序的過程是先用javac編譯,然後用java解釋。而一經編譯成功後,就可以直接用java.exe隨處解釋運行了。

網頁瀏覽器只是自帶了javascript的解釋器,其他語言的解釋器沒有。至於有些語言如java等可以在瀏覽器上運行是因為瀏覽器通過插件的形式支持的

『陸』 北大青鳥java培訓:位元組碼指令的編譯與執行

java編程開發是目前市場上使用范圍非常廣泛的一種編程開發語言。
今天我們就一起來了解一下,在java編程中關於位元組碼的一些指令的編譯與執行方法。
java文件編譯後的class文件,java跨平台的中間層,JVM通過對位元組碼的解釋執行(執行模式,還有JIT編譯執行,下面講解),屏蔽對操作系統的依賴。
一個位元組(8位)可以儲存256中不同的指令,這樣的指令就是位元組碼,java所有指令有200個左右,這些指令組成了位元組碼文件(.class)。
一、位元組碼的主要指令:.class文件裡面的十六進制文件,其中CAFEBABE是標志這個文件為java的編譯後的文件,00000034代表版本號,01670700一個位元組(8位)就是一個位元組指令,由於數值指令太難看懂,我們可以用javap將指令翻譯為助記指令。
1、載入或儲存指令在棧幀中,通過指令操作數據在局部變數表與操作棧間傳遞。
ILOAD、ALOAD:將int、對象引用類型從局部變數表壓入操作棧頂;ISTORE、ASTORE:將int、對象引用類型從操作棧頂儲存到局部變數表裡;ICONST、BIPUSH、SIPUSH、LDC:將常亮載入到操作棧頂。
2、運算指令對操作棧上的值進行運算,並把結果寫入操作棧頂,如IADD、IMUL。
3、類型轉換指令I2L、D2F4、對象創建與訪問指令NEW除了位元組碼指令外,湖北電腦培訓http://www.kmbdqn.cn/認為還包括像LINENUMBER儲存位元組碼與源碼對應,方便調試定位;LOCALVARIABLE儲存當前方法使用到的局部表量表。
二、java源碼文件轉化為位元組碼(.class)文件的過程JAVA源文件---------->詞法解析---------->語法解析---------->語義分析--------->生成位元組碼--------->位元組碼文件詞法分析:根據空格分割出單詞、操作符等,形成token信息流;語法分析:根據token流和java語法規范生成語法樹;語義分析:檢查關鍵字、類型匹配是否正確;

『柒』 JVM_位元組碼文件(ClassFile)詳解

我們知道 javac 命令可以將 .java 文件編譯成 .class 文件,而這個 Class 文件 中包含了 Java虛擬機 指令集、符號表以及若干其他輔助信息;最終將在 Java虛擬機 運行。

本文是以 JVM8 為例的。

每一個 Class文件 都有如下的 ClassFile 文件結構:

先簡單介紹一下 ClassFile 文件結構各部分含義:

描述符是表示欄位或方法類型的字元串。

欄位描述符表示類、實例或局部變數的類型。

從上面文法可以看出,欄位描述符中一共有三個類型:

方法描述符包含 0 個或者多個參數描述符以及一個返回值描述符。

看了描述符,可能大家有點疑惑,泛型信息怎麼表示啊?

常量池的通用格式如下:

目前 JVM8 中一共用 14 種常量類型,分別如下:

我們知道要使用一個欄位或者調用一個方法,就必須知道欄位或者方法所屬類符號引用,和欄位的名字和類型,方法的名字和方法參數類型以及方法返回值類型。
但是我們知道類是能繼承的,那麼子類調用父類的方法或者欄位,這里的所屬類符號引用,到底是子類本身還是父類的呢?

我們知道類,方法,欄位都有不同的訪問標志,在 Class 文件 中使用一個 u2 類型數據項來存儲,也就是最多可以有 16 個不同標志位。
在類,方法,欄位中有相同的標志,也有不同的標志,總體規劃,我們可以藉助 Modifier 類的源碼來了解:

在 Modifier 類中,類的訪問標志:

我們知道在 java 中類可以用的修飾符有: public , protected , private , abstract , static , final , strictfp 。

但是我們再看 Class 文件 中類的訪問標志:

仔細看,你會發現有些不同點:

在 Modifier 類中,欄位的訪問標志:

我們知道在 java 中欄位可以用的修飾符有: public , protected , private , static , final , transient 和 volatile 。

但是我們再看 Class 文件 中欄位的訪問標志:

Class 文件 中欄位的訪問標志和 java 中欄位的修飾符差不多,只是多了 ACC_SYNTHETIC 和 ACC_ENUM 兩個標志。

在 Modifier 類中,方法的訪問標志:

我們知道在 java 中方法可以用的修飾符有:
public , protected , private , abstract , static , final , synchronized , synchronized 和 strictfp 。

但是我們再看 Class 文件 中方法的訪問標志:

欄位詳情 field_info 的格式如下:

方法詳情 method_info 的格式如下:

關於 Class 文件 中屬性相關信息,我們再後面章節介紹。

我們可以通過 javap 的命令來閱讀 Class 文件 中相關信息。

這個是最簡單的一個類,沒有任何欄位和方法,只繼承 Object 類,我們來看看它編譯後的位元組碼信息,通過 javap -p -v T.class 的命令:

我們重點關注常量池相關信息,會發現雖然 T.class 很乾凈,但是也有 15 個常量,來我們依次分析:

與之前的例子相比較,多了一個欄位和方法,那麼得到的位元組碼信息如下:

但是你會發現常量池中怎麼沒有這個欄位 name 的 CONSTANT_Fieldref_info 類型的常量呢?
那是因為我們沒有使用這個欄位。

多寫了一個方法 test1 來調用 name 欄位和 test 方法,那麼得到的位元組碼信息如下:

這里定義一個父類 TParent ,有一個公共欄位 name 和方法 say 。子類

『捌』 JAVA編程中source code和bytecode有什麼區別,不要太詳細的

soucecode是源代碼,也就是後綴名為java的文件bytecode是二進制文件,也就是後綴名為class的文件
希望能看看我寫的《java編程那些事兒》一書

『玖』 什麼是位元組碼文件

位元組碼文件就是以.class文件結尾的文件,是通過javac命令編譯過生成的。因為java不是編譯型語言,所以它需要去解釋位元組碼文件才能夠運行。

『拾』 Java里的位元組碼和源代碼分別啥意思,和起到什麼左右

/*java是一門高級編程語言,是用來寫程序代碼的。
用java寫的文本(字元串序列)就是源代碼。
計算機不能直接執行源代碼,必須用一個叫編譯器的程序(javac.exe)將源代碼
翻譯成位元組碼,然後讓一個叫解釋器的程序(java.exe)去執行位元組碼,即運行程序。

下面的就是一個小程序的源代碼,功能是輸出九九乘法表。

下圖中的Test.class就是這個源代碼文件翻譯後的由位元組碼組成的文件。
而最下面的那個黑框就是程序執行後的結果。
java Test就是在執行Test.class位元組碼文件,即運行這個程序。
*/
//這下面的就是源代碼
public class Test {
public static void main(String[] args) {
int i,j;

for(i=1;i<=9;i++) {
for(j=1;j<=i;j++)
System.out.printf("%dx%d=%-4d",j,i,j*i);
System.out.println();
}
}
}

閱讀全文

與位元組碼文件該如何理解相關的資料

熱點內容
t8cad文件怎麼打開 瀏覽:275
英語趣配音網路未連接 瀏覽:740
linuxdeb文件安裝 瀏覽:153
word如何在箭頭上寫字 瀏覽:821
安全刪除數據為什麼要重寫硬碟 瀏覽:873
稅務系統網路與信息安全應急保障工作框架 瀏覽:407
淘寶背景代碼生成 瀏覽:649
小學特色託管編程圖形如何 瀏覽:748
編程實驗分析怎麼寫 瀏覽:58
滑鼠編程宏怎麼設置 瀏覽:100
怎麼清除百度登錄過網站 瀏覽:503
linuxl2 瀏覽:116
蘋果升級一直重啟怎麼解決 瀏覽:827
農商銀行app怎麼登錄不上去 瀏覽:47
查看已連接寬頻密碼 瀏覽:822
日本創建購物網站需要什麼 瀏覽:723
數據拐點什麼時候出來 瀏覽:640
怎麼做到徹底理解編程語言 瀏覽:167
機器人和程序編程哪個好 瀏覽:563
怎麼改蘋果手機icloud賬號和密碼 瀏覽:526

友情鏈接