《自己動手寫Java虛擬機器》學習筆記(八)陣列和字串

NO IMAGE

第八章 陣列和字串

8.1陣列概述

如果陣列元素是基本型別,就稱之為基本型別陣列,否則,如果陣列元素是引用型別,就稱之為引用型別陣列。基本型別陣列肯定都是一維陣列,如果引用型別陣列元素也是陣列,那麼它就是多維陣列。

在jvm中,陣列類和普通的類是不同的。首先,普通的類從class問價載入,但是陣列類由jvm在執行時生成。陣列類名是左方括號 陣列的型別描述符;陣列的型別描述符就是類名本身。比如int[]的類名就是[I,Object[]的類名就是[Ljava/lang/Obejct;

其次,建立陣列的方式和建立普通物件的方式不同。普通物件由new指令建立,然後由建構函式初始化。基本型別陣列由newarray指令建立;引用型別陣列由anewarray指令建立;另外還有一個專門的multianewarray用於建立多維陣列。

最後,陣列和普通物件存放的資料也是不同的。普通物件中存放的是例項變數,通過putfiled和getfiled存取。陣列物件中存放的則是陣列元素,通過<t>aload和<t>astore系列指令按索引存取。另外有一個arraylength指令,用於獲取陣列長度。

8.2 陣列實現

和普通物件一樣,陣列也是分配在堆中的,通過引用來使用。

建立陣列物件時,如果類不是陣列類,就終止程式;否則要根據陣列型別建立陣列物件

這時我們要修改類載入器,讓他可以載入陣列類。

8.3 陣列相關指令

newarray用來建立基本型別陣列。它需要兩個運算元。第一個運算元是一個uint8整數,在位元組碼中緊跟在操作碼後面,表示要建立那種型別的陣列。java虛擬機器規範稱呼這個值為atype,並規定了其有效值,具體可見jvm規範。第二個運算元是count,從運算元棧中彈出,表示陣列長度。如果這個count小於0,則拋異常。否則根據atype值使用當前類的類載入器載入陣列類,然後建立陣列物件並推入運算元棧。

anewarray用來建立引用資料型別。他也需要兩個運算元。第一個運算元是uint16索引,來自位元組碼。通過這個索引可以從當前類的執行時常量池中找到一個類符號引用,解析這個類符號引用就可以得到陣列元素的類。第二個運算元是陣列長度,從運算元棧中彈出。

arraylength用來獲取陣列長度。他只需要一個運算元,即從運算元棧頂彈出陣列引用。如果陣列引用是null,拋異常。否則取陣列長度推入運算元棧頂。

<t>aload系列。以aaload為例,從運算元棧彈出第一個運算元:陣列索引,然後彈出第二個運算元:陣列引用。如果陣列引用時null拋異常。如果索引小於0,或者大於陣列長度拋異常。如果一切正常,按索引取出陣列元素,推入運算元棧頂。

<t>astore系列。以iastore為例,三個運算元:賦給陣列元素的值、陣列索引、陣列引用。依次從運算元棧中彈出。檢查與<taload>一樣。如果一切正常,則按照索引給陣列元素賦值。

multianewarray建立多維陣列。第一個運算元是uint16索引,通過這個索引可以從執行時常量池中找到一個類符號引用,解析這個引用就可以得到多維陣列類,注意是陣列類!第二個運算元是unit8整數,表示陣列維度。這兩個運算元在位元組碼中緊跟在指令操作碼後面。還需要從運算元棧中彈出n個整數,分別代表每一維度的陣列長度。如果他們中任意一個小於0,都跑出異常。

修改instanceof和checkcast指令。注意:①陣列可以強制轉化成為Object型別(因為陣列類的超類是Object)。②陣列可以強制轉化成為Cloneable和Serializable型別(因為實現了這兩個介面)。③如果TC和SC是同一個基本型別,或者TC和SC都是引用型別且SC可以強制轉化為TC,則[]SC陣列可以強制型別轉化為[]TC陣列。

8.4 字串

在class檔案中,字串是以MUTF8格式儲存的。在JVM執行期間,字串是以java.lang.String(後面簡稱String)物件形式存在的。而在String物件內部,又是以UTF16格式儲存的。

String類有兩個例項變數。其中一個是value,型別是字元陣列,用於存放UTF16編碼後的字元序列。另一個事hash,快取計字串的雜湊碼。

字串物件是不可變的,一旦構造好了之後,就無法再改變其狀態(這裡指的是value欄位)。

為了節約記憶體,JVM內部維護了一個字串池。String類提供了intern()方法,可以把自己放入字串池。

實現的時候用了一個hack的方式。如果java字串已經在池中,直接返回即可。否則建立一個java字串,把它的value值設定成傳來的字元陣列,最後把java字串放入池中。

完善ldc指令。如果ldc檢視從執行時常量池中載入字串常量,則先通過常量拿到Go字串,然後把它轉化成為Java字串例項並把引用推倒運算元棧頂。

8.5 Go語言語法

interface{}型別很想C語言void*,該型別變數可以容納任何型別的值。

Go字串是UTF8格式。