轉(zhuǎn)帖|其它|編輯:郝浩|2011-02-09 15:35:32.000|閱讀 470 次
概述:本文主要介紹怎樣用Jvm處理Java數(shù)組,希望對大家有幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
記得vamcily 曾問我:“為什么獲取數(shù)組的長度用.length(成員變量的形式),而獲取String的長度用.length()(成員方法的形式)?”
我當(dāng)時一聽,覺得問得很有道理。做同樣一件事情,為什么采用兩種風(fēng)格迥異的風(fēng)格呢?況且,Java中的數(shù)組其實是完備(full- fledged)的對象,直接暴露成員變量,可能不是一種很OO的風(fēng)格。那么,設(shè)計Java的那幫天才為什么這么做呢?
帶著這個疑問,我查閱了一些資料,主要是關(guān)于“JVM是如何處理數(shù)組”的。
數(shù)組對象的類是什么?
既然數(shù)組都是對象,那么數(shù)組的類究竟是什么呢?當(dāng)然不是java.util.Arrays啦!我們以int一維數(shù)組為例,看看究竟。
public class Main {
public static void main(String args[]){
int a[] = new int[10]; Class clazz = a.getClass();
System.out.println(clazz.getName());
}
}
在SUN JDK 1.6上運(yùn)行上述代碼,輸出為:
[I
看起來數(shù)組的類很奇怪,非但不屬于任何包,而且名稱還不是合法的標(biāo)識符(identifier)。具體的命名規(guī)則[1]可以參見 java.lang.Class.getName()的javadoc。簡單的說,數(shù)組的類名由若干個'['和數(shù)組元素類型的內(nèi)部名稱組成,'['的數(shù)目 代表了數(shù)組的維度。
具有相同類型元素和相同維度的數(shù)組,屬于同一個類。如果兩個數(shù)組的元素類型相同,但維度不同,那么它們也屬于不同的類。如果兩個數(shù)組的元素類型 和維度均相同,但長度不同,那么它們還是屬于同一個類。
數(shù)組的類有哪些成員呢?
既然我們知道了數(shù)組的類名是什么,那么就去看看數(shù)組的類究竟是什么樣的吧?有哪些成員變量?有哪些成員方法?length這個成員變量在哪?是 不是沒有l(wèi)ength()這個成員方法?
找來找去,在JDK的代碼中沒有找打'[I'這個類。想想也對,'[I'都不是一個合法的標(biāo)識符,肯定不會出現(xiàn)public class [I {...}這樣的Java代碼。我們暫且不管[I類是誰聲明的,怎么聲明的,先用反射機(jī)制一探究竟吧。
public class Main {
public static void main(String[] args) {
int a[] = new int[10]; Class clazz = a.getClass();
System.out.println(clazz.getDeclaredFields().length);
System.out.println(clazz.getDeclaredMethods().length);
System.out.println(clazz.getDeclaredConstructors().length);
System.out.println(clazz.getDeclaredAnnotations().length);
System.out.println(clazz.getDeclaredClasses().length);
System.out.println(clazz.getSuperclass());
}
}
在SUN JDK 1.6上運(yùn)行上述代碼,輸出為:
0 0 0 0 0 class java.lang.Object 可見,[I這個類是java.lang.Object的直接子類,自身沒有聲明任何成員變量、成員方法、構(gòu)造函數(shù)和Annotation,可以說,[I就 是個空類。我們立馬可以想到一個問題:怎么連length這個成員變量都沒有呢?如果真的沒有,編譯器怎么不報語法錯呢?想必編譯器對 Array.length進(jìn)行了特殊處理哇!
數(shù)組的類在哪里聲明的?
先不管為什么沒有l(wèi)ength成員變量,我們先搞清楚[I這個類是哪里聲明的吧。既然[I都不是合法的標(biāo)識符,那么這個類肯定在Java代碼中 顯式聲明的。想來想去,只能是JVM自己在運(yùn)行時生成的了。JVM生成類還是一件很容易的事情,甚至無需生成字節(jié)碼,直接在方法區(qū)中創(chuàng)建類型數(shù)據(jù),就差不 多完工了。
還沒有實力去看JVM的源代碼,于是翻了翻The JavaTM Virtual Machine Specification Second Edition,果然得到了驗證,相關(guān)內(nèi)容參考5.3.3 Creating Array Classes。
規(guī)范的描述很嚴(yán)謹(jǐn),還摻雜了定義類加載器和初始化類加載器的內(nèi)容。先不管這些,簡單概括一下:
類加載器先看看數(shù)組類是否已經(jīng)被創(chuàng)建了。如果沒有,那就說明需要創(chuàng)建數(shù)組類;如果有,那就無需創(chuàng)建了。
如果數(shù)組元素是引用類型,那么類加載器首先去加載數(shù)組元素的類。
JVM根據(jù)元素類型和維度,創(chuàng)建相應(yīng)的數(shù)組類。
呵呵,果然是JVM這家伙自個偷偷創(chuàng)建了[I類。JVM不把數(shù)組類放到任何包中,也不給他們起個合法的標(biāo)識符名稱,估計是為了避免和JDK、第 三方及用戶自定義的類發(fā)生沖突吧。
再想想,JVM也必須動態(tài)生成數(shù)組類,因為Java數(shù)組類的數(shù)量與元素類型、維度(最多255)有關(guān),相當(dāng)相當(dāng)多了,是沒法預(yù)先聲明好的。
居然沒有l(wèi)ength這個成員變量!
我們已經(jīng)發(fā)現(xiàn),偷懶的JVM沒有為數(shù)組類生成length這個成員變量,那么Array.length這樣的語法如何通過編譯,如何執(zhí)行的呢?
讓我們看看字節(jié)碼吧!編寫一段最簡單的代碼,使用jclasslib查看字節(jié)碼。
public class Main {
public static void main(String[] args) {
int a[] = new int[2]; int i = a.length;
}
}
使用SUN JDK 1.6編譯上述代碼,并使用jclasslib打開Main.class文件,得到main方法的字節(jié)碼:
0 iconst_2 //將int型常量2壓入操作數(shù)棧
1 newarray 10 (int) //將
2彈出操作數(shù)棧,作為長度,創(chuàng)建一個元素類型為int, 維度為1的數(shù)組,并將數(shù)組的引用壓入操作數(shù)棧
3 astore_1 //將數(shù)組的引用從操作數(shù)棧中彈出,保存在索引為1的局部變量(即a)中
4 aload_1 //將索引為1的局部變量(即a)壓入操作數(shù)棧
5 arraylength //從操作數(shù)棧彈出數(shù)組引用(即a),并獲取其長度(JVM負(fù)責(zé)實現(xiàn)如何獲取),并將長度壓入操作數(shù)棧
6 istore_2 //將數(shù)組長度從操作數(shù)棧彈出,保存在索引為2的局部變量(即i)中
7 return //main方法返回 可見,在這段字節(jié)碼中,根本就沒有看見length這個成員變量,獲取數(shù)組長度是由一條特定的指令arraylength實現(xiàn)(怎么實現(xiàn)就不管了,JVM 總有辦法)。
編譯器對Array.length這樣的語法做了特殊處理,直接編譯成了arraylength指令。另外,JVM創(chuàng)建數(shù)組類,應(yīng)該就是由 newarray這條指令觸發(fā)的了。
很自然地想到,編譯器也可以對Array.length()這樣的語法做特殊處理,直接編譯成arraylength指令。這樣的話,我們就可 以使用方法調(diào)用的風(fēng)格獲取數(shù)組的長度了,這樣看起來貌似也更加OO一點。那為什么不使用Array.length()的語法呢?也許是開發(fā)Java的那幫 天才對.length有所偏愛,或者拋硬幣拍腦袋隨便決定的吧。 形式不重要,重要的是我們明白了背后的機(jī)理。
Array in Java
最后,對Java中純對象的數(shù)組發(fā)表點感想吧。
相比C/C++中的數(shù)組,Java數(shù)組在安全性要好很多。C/C++常遇到的緩存區(qū)溢出或數(shù)組訪問越界的問題,在Java中不再存在。因為 Java使用特定的指令訪問數(shù)組的元素,這些指令都會對數(shù)組的長度進(jìn)行檢查。如果發(fā)現(xiàn)越界,就會拋出 java.lang.ArrayIndexOutOfBoundsException。
Java數(shù)組元素的靈活性比較大。一個數(shù)組的元素本身也可以是數(shù)組,只要所有元素的數(shù)組類型相同即可。我們知道數(shù)組的類型和長度無關(guān),因此元素 可以是長度不同的數(shù)組。這樣,Java的多維數(shù)組就不一定是規(guī)規(guī)矩矩的矩陣了,可以千變?nèi)f化。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載