class 和 dex 的區別

class 文件結構深入解析

什麼是 class 文件

​ 能夠被 JVM 識別,加載並執行的文件格式,他就類似於 mp3 的格式,只能運用於特定的地方,如 mp3 只能被播放,而 class 文件則是需要被 JVM 進行加載。

​ 並不是只有 java 語言才能生成 class 文件,當然還有其他的一下語言:

在這裏插入圖片描述

如何生成一個 class文件

​ 通過 ide 自動生成 class 文件,通過 run 來執行 calss 文件

​ 通過 javac 生成 class 文件 ,通過 java 命令去執行 class 文件

class 文件的作用

​ 記錄一個類文件中的所有信息,記住是所有的信息,包括類名稱,方法,變量等,class 中記錄的信息遠遠多於java源代碼中的信息。例如:我們並沒有在類中定義 this、super 這樣的關鍵字,但是我們可以使用,這是因爲 java 虛擬機在生成 class 文件時已經幫我們記錄在裏面了。

class 文件結構

​ 一種8位字節的二進制文件

​ 各個數據按順序緊密的排列,沒有間隙,不想有些文件,爲了讀取方便,則不會讓數據緊密排列。而 class 文件這樣的好處就是 體積小。

​ 每個類或者接口都單獨佔據一個 class 文件

​ class 的文件格式採用的是類似結構體的結構來存儲數據,這種結構只有兩種數據類型:無符號豎和表,其中無符號數屬於基本的數據類型,u1,u2,u4,u8 來分別代表 一個字節 ,2,4,8個字節。無符號數可以用阿里描述數字,索引引用,數量值或者 utf-8構成的字符串值,而表是由多個無符號數或其他表構成的複合數據結構,所有的表都以 _info 結尾,表用於描述有層次關係的複合結構數據類型,其實整個 class 文件就是一張表。(但是我覺得更像結構體)

​ 下面看一下具體的結構

類型 名稱 數量 作用
u4(無符號四字節) magic 1 加密段,當前calss 文件是否被串改過
u2 minor_version 1 最小可以被那個版本的 jdk所加載
u2 major_version 1 當前calss是別那個版本生成的
u2 constant_pool_count 1 常量池的數量,通常只有一個
cp_info constant_pool constant_poll_count - 1 真正的常量池,它內部包含了很多內容,下面有詳細解釋
u2 access_flags 1 作用域標誌,例如這個 class 文件是 public 還是 public final 類型的 等等。下面會放一張圖
u2 this_class 1 this,jvm 在生成 class 的時候幫我們補充了這個字段,這就是爲什麼我們沒有定義它卻能夠使用他了
u2 super_class 1 和上面的 this 一樣
u2 interfaces_count 1 數量
u2 interfaces interfaces_count 這兩個表示當前類實現了多少個接口,注意:只算直接的,間接的不算,如不會計算父類實現的接口。
u2 fields_count 1 數量
field_info fields fields_count 當前class中的所有成員變量,他裏面還包含了其他的信息,如 類型,所屬的類等
u2 medthods_count 1 數量
medthod_info methods methods_sount 記錄了class 中所有的方法,包含了其他信息。
u2 attribute_count 1 數量
attribute_info attributes attributes_count 記錄類屬性相關的,上面沒有包含的都會在這裏面,如註解等。

我們看一下這個表格,class 文件中定義了很多字段,這些字段又包含了非常多的內容。通過這些字段,jvm 就可以找到我們類中所有的內容

access_flags :作用域

在這裏插入圖片描述

這個圖清楚地表示了 access_flags 字段的作用域。

constant_pool:常量池,下面是幾種常用的類型

​ CONSTANT_Integer_info

​ CONSTANT_Long_info

​ CONSTANT_String_info

​ // 下面這幾個裏面存儲的並不是真的內容,而是索引,這些索引最終指向的就是上面這幾種類型,所以我們所有的信息都是存在常量池中的。

​ CONSTANT_Class_info //類信息,例如名字等,引用到類的一些信息等

​ CONSTANT_Fieldref_info //類中變量信息

​ CONSTANT_Methodref_info //類中方法信息

我們可以通過工具來查看一下 class 文件內容,工具名字爲 010 Editor。
在這裏插入圖片描述

struct cp_info_constant_pool[0] 中的 u2,代表的是無符號數,u2 代表訪問標誌,如 u2 class_index 指向的就是這個方法所屬的類。相當於索引吧,

注意看 u1 tag:

​ 在常量池中有14種類型,這個常量都是一個表,每一個表都有各自組成的機構,這寫常量都有一個特點,每個常量的開始都是一個用 u1 類型的無符號數表示的標誌位,如下表所示:
在這裏插入圖片描述

常量池中第一個 struct cp_info constant_poll[0] ,他的後面是 Methodref ,標誌是 10 ,我們和上面的表對比一下,找到第 10 個,也是 Methodref ,通過這個表,我們可以查看 u1 tag 到底表示的是那種類型。
在這裏插入圖片描述
如上面的 fields_count 爲1,下面就有一個 struct field_info 的表,裏面保存了字段的信息,在紅框的下面,methods_count 爲 2,下面就有 methods[0] 和 methods[1]表,來表示這兩個方法。這也就對應了上面的表。

class 文件弊端

​ 內存佔用大,不適合移動端

​ 堆棧的加載模式,加載速度慢

​ 文件 IO 操作多,類查找慢 。每次加載類的時候都要去尋找和加載

dex文件結構深入解析

什麼是 dex 文件

​ 能夠被 DVM 所識別,加載並執行的文件格式,dex 文件可以 用 c 和c++ 進行生成

如何生成一個 dex 文件

​ 通過 IDE 自動幫我們 build 生成

​ 手動通過 dx 命令生成 dex 文件

dex 文件的作用

​ 記錄整個工程中所有類文件的信息,是整個工程(class 則是記錄當前類的信息)

dex 文件結構

​ 一種 8 位字節的二進制流文件

​ 各個數據按順序緊密的排列,無間隙

​ 整個應用中所有的 java 源文件都放在一個dex中,這裏不考慮 multidex

在這裏插入圖片描述

dex 文件頭

在這裏插入圖片描述
在這裏插入圖片描述

  1. magic :一般稱爲魔數,他可以判斷當前的 dex 文件是否有效,可以看到他的 大小就是 8 h,也就是他用了 8個1字節的無符號數表示。

  2. checksum : dex 文件的校驗和,通過它可以判斷 dex 文件是否被損壞

  3. signature[] : 用於校驗 dex 文件,其實就是把整個 dex 文件用 SHA-1 簽名得到的一個值,

  4. file_size : 表示真個文件的大小,佔用了4個字節

  5. header_size : 表示 dex 頭部分的大小,佔用4字節

  6. endian_tga :字節序標記,用於指定 dex 運行環境的 cpu,預設值爲0x123456789

  7. link_size 和 link_off :分別指定了鏈接段的大小和文件的偏移,通常都爲0

  8. map_off :指定了 DexMapList 的文件偏移

  9. string_ids_size 和 string_ids_offf:這兩個字段表示了 dex 文件中所有用到的字符串的個數和位置偏移。通過轉換 size 爲16,偏移爲112。

​ 下面我們可以看一下 string_ids_size 的16進制和off 的16進制,分別爲10 00 00 00 和 70 00 00 00,前者轉換10進制後爲 16,說明 size 有 16 個字符串,off 則代表偏移 70h , 最後一個空字符“0”表示的是結尾 。然後我們找到70h 看一下
在這裏插入圖片描述
下面我們看一下70h
在這裏插入圖片描述

從70 開始,到 AOh 結束,所選中的都是 字符串的偏移量,通過這些偏移量我們才能找字符串,看一下上面第二個框,是 字符串的索引,可以看到他也是從70h 開始,大小是40h,也就是到A0h。在這段區域內保存的纔是真正的字符串索引。我們可以看一下70h 第一個 92 01 00 00 ,他代表的偏移地址就是 0192h,接着我們找一下 0192h
在這裏插入圖片描述

可以看到我一共選中了 8個字節,在這8個字節中我們可以用到的有6個,最開始的 06 則表示我們用到的個數,最後的 0 表示的是字符串結尾,下面我們把他們進行轉換一下:

十六進制 3C 69 6E 69 74 3E
十進制 60 105 110 105 116 62
ASCII < i n i t >

在線進制轉換表

在線 ASCII 對照表

通過上面這種方式我們就可以找到字符串的16進制,並轉換爲對應的字符串。

其他的都一樣,我們也沒有必要像上面遮這樣找,其實我們可以直接在索引區找到對應的值。例如上面這個例子:
在這裏插入圖片描述
這裏的數據是從 163開始的,是因爲他並沒有及時前面的 06 ,這個06至少代表後面要用到 6 個而已。

從 9 往下基本都是這個樣子的。通過上面這種方法就可以查到具體的位置。

索引區

類型索引:

在這裏插入圖片描述
如 Hellow 類索引,Object 索引,String 索引的。這些都是我們所引用到的。

方法原型索引 :

在這裏插入圖片描述
字段索引:
]
方法索引:
在這裏插入圖片描述
如上面的 main 方法 ,printStream 打印方法等。。他會記錄當前類所引用的方法索引和繼承的方法索引

類索引:
g)]
整個dex 文件中所有類索引

map 列表:
在這裏插入圖片描述
他是對整個頭文件的一個校驗

數據區

​ 每個索引對應的值就是數據了。

最後看一下整個 dex 文件

在這裏插入圖片描述

Class 和 Dex 的區別

ass 文件是一個表。這個表只記錄了當前java的信息。

dex 將文件劃分爲了 三個區域,這三個區域存儲了整個工程中所有的java 文件的信息,所以 dex 在類越來越多的時候優勢就提現出來了。他只要一個dex文件,很多區域都是可以進行復用的,減少了dex 文件的大小。

本質上他們是一樣的,dex 是從 class 文件演變而來的,但是 calss 中存在了許多沉餘信息,dex 去掉了沉餘信息,並進行了整合

在這裏插入圖片描述

參考:https://www.jianshu.com/p/e5062d62a3d1
慕課網視頻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章