class文件中的特殊字符串java
首先說明一下, 所謂的特殊字符串出如今class文件中的常量池中, 因此在上一篇博客中, 只是對常量池介紹了一個大概。 本着按部就班和減小跨度的原則, 首先把class文件中的特殊字符串作一個詳細的介紹, 而後再回過頭來繼續講解常量池。 數組
在上文中, 咱們提到特殊字符串是常量池中符號引用的一部分, 至於符號引用的概念, 會在之後提到。 如今咱們將重點放在特殊字符串上。 特殊字符串包括三種: 類的全限定名, 字段和方法的描述符, 特殊方法的方法名。 下面咱們就分別介紹這三種特殊字符串。學習
(1) 類的全限定名spa
在常量池中, 一個類型的名字並非咱們在源文件中看到的那樣, 也不是咱們在源文件中使用的包名加類名的形式。 源文件中的全限定名和class文件中的全限定名不是相同的概念。 源文件中的全新定名是包名加類名, 包名的各個部分之間,包名和類名之間, 使用點號分割。 如Object類, 在源文件中的全限定名是java.lang.Object 。 而class文件中的全限定名是將點號替換成「/」 。 例如, Object類在class文件中的全限定名是 java/lang/Object 。 若是讀者以前沒有接觸過class文件格式, 是class文件格式的初學者, 在這裏沒必要知道全限定名在class文件中是如何使用的, 只須要知道, 源文件中一個類的名字, 在class文件中是用全限定名錶述的。 接口
(2) 描述符ci
咱們知道在一個類中能夠有若干字段和方法, 這些字段和方法在源文件中如何表述, 咱們再熟悉不過了。 既然如今咱們要學習class文件格式, 那麼咱們就要問, 一個字段或一個方法在class文件中是如何表述的? 在本文中, 咱們會討論方法和字段在class文件中的描述。 方法和字段的描述符並不會把方法和字段的全部信息全都描述出來, 畢竟描述符只是一個簡單的字符串。 字符串
在講解描述符以前, 要先說明一個問題, 那就是全部的類型在描述符中都有對應的字符或字符串來對應。 好比, 每種基本數據類型都有一個大寫字母作對應, void也有一個大寫字符作對應。 下表是void和基本數據類型在描述符中的對應。get
基本數據類型和void類型 | 類型的對應字符 |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
boolean | Z |
void | V |
基本上都是以類型的首字符變成大寫來對應的, 其中long和boolean是特例, long類型在描述符中的對應字符是J, boolean類型在描述符中的對應字符是Z 。 源碼
基本類型和void在描述符中都有一個大寫字符和他們對應, 那麼引用類型(類和接口,枚舉)在描述符中是如何對應的呢? 引用類型的對應字符串(注意, 引用類型在描述符中使用一個字符串作對應) , 這個字符串的格式是:博客
「L」 + 類型的全限定名 + 「;」
注意,這三個部分之間沒有空格, 是緊密排列的。 如Object在描述符中的對應字符串是: Ljava/lang/Object; ; ArrayList在描述符中的對應字符串是: Ljava/lang/ArrayList; ; 自定義類型com.example.Person在描述符中的對應字符串是: Lcom/example/Person; 。
咱們知道, 在Java語言中數組也是一種類型, 一個數組的元素類型和他的維度決定了他的類型。 好比, 在 int[] a 聲明中, 變量a的類型是int[] , 在 int[][] b 聲明中, 變量b的類型是int[][] , 在 Object[] c 聲明中, 變量c的類型是Object[] 。既然數組是類型, 那麼在描述符中, 也應該有數組類型的對應字符串。 在class文件的描述符中, 數組的類型中每一個維度都用一個 [ 表明, 數組類型整個類型的對應字符串的格式以下:
若干個「[」 + 數組中元素類型的對應字符串
下面舉例來講名。 int[]類型的對應字符串是: [I 。 int[][]類型的對應字符串是: [[I 。 Object[]類型的對應字符串是: [Ljava/lang/Object; 。 Object[][][]類型的對應字符串是: [[[Ljava/lang/Object; 。
介紹完每種類型在描述符中的對應字符串, 下面就開始講解字段和方法的描述符。
字段的描述符就是字段的類型所對應的字符或字符串。 如: int i 中, 字段i的描述符就是 I 。 Object o中, 字段o的描述符就是 Ljava/lang/Object; 。 double[][] d中, 字段d的描述符就是 [[D 。
方法的描述符比較複雜, 包括全部參數的類型列表和方法返回值。 它的格式是這樣的:
(參數1類型 參數2類型 參數3類型 ...)返回值類型
其中, 無論是參數的類型仍是返回值類型, 都是使用對應字符和對應字符串來表示的, 而且參數列表使用小括號括起來, 而且各個參數類型之間沒有空格, 參數列表和返回值類型之間也沒有空格。
下面舉例說明(此表格來源於《深刻Java虛擬機》)。
boolean regionMatches(boolean ignoreCase, int toOffset, String other, int ooffset, int len)
([BII)I int read(byte[] b, int off, int len )
()[[Ljava/lang/Object; Object[][] getObjectArray()
方法描述符 | 方法聲明 |
()I | int getSize() |
()Ljava/lang/String; | String toString() |
([Ljava/lang/String;)V | void main(String[] args) |
()V | void wait() |
(JI)V | void wait(long timeout, int nanos) |
(ZILjava/lang/String;II)Z | boolean regionMatches(boolean ignoreCase, int toOffset, String other, int ooffset, int len) |
([BII)I | int read(byte[] b, int off, int len ) |
()[[Ljava/lang/Object; | Object[][] getObjectArray() |
(3) 特殊方法的方法名
首先要明確一下, 這裏的特殊方法是指的類的構造方法和類型初始化方法。 構造方法就不用多說了, 至於類型的初始化方法, 對應到源碼中就是靜態初始化塊。 也就是說, 靜態初始化塊, 在class文件中是以一個方法表述的, 這個方法一樣有方法描述符和方法名。
類的構造方法的方法名使用字符串 <init> 表示, 而靜態初始化方法的方法名使用字符串 <clinit> 表示。 除了這兩種特殊的方法外, 其餘普通方法的方法名, 和源文件中的方法名相同。
總結
到此爲止, 關於特殊字符串就講解完了。 最後作一下總結:
class文件中的特殊字符串包括類(包括接口, 枚舉)的全限定名, 字段的描述符和方法的描述符。 其中類的全限定名比較簡單易於理解, 字段和方法的描述符因爲涉及到每種類型的映射, 可能稍顯複雜。 要理解描述符, 主要是要熟記每種類型(包括8種基本數據類型,類類型, 數組類型和void)在描述符中所對應的描述字符或字符串。
還有一點須要注意, 就是方法和字段的描述符中, 不包括字段名和方法名, 字段描述符中只包括字段類型, 方法描述符中只包括參數列表和返回值類型。