国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
有關(guān)JVM處理Java數(shù)組方法的思考

記得vamcily 曾問(wèn)我:“為什么獲取數(shù)組的長(zhǎng)度用.length(成員變量的形式),而獲取String的長(zhǎng)度用.length()(成員方法的形式)?”

我當(dāng)時(shí)一聽(tīng),覺(jué)得問(wèn)得很有道理。做同樣一件事情,為什么采用兩種風(fēng)格迥異的風(fēng)格呢?況且,Java中的數(shù)組其實(shí)是完備(full-fledged)的對(duì)象,直接暴露成員變量,可能不是一種很OO的風(fēng)格。那么,設(shè)計(jì)Java的那幫天才為什么這么做呢?

帶著這個(gè)疑問(wèn),我查閱了一些資料,主要是關(guān)于“JVM是如何處理數(shù)組”的。

數(shù)組對(duì)象的類是什么?

既然數(shù)組都是對(duì)象,那么數(shù)組的類究竟是什么呢?當(dāng)然不是java.util.Arrays啦!我們以int一維數(shù)組為例,看看究竟。

  1. public class Main {   
  2. public static void main(String args[]){   
  3. int a[] = new int[10]; Class clazz = a.getClass();   
  4. System.out.println(clazz.getName());   
  5. }   
  6. }  
  7.  

在SUN JDK 1.6上運(yùn)行上述代碼,輸出為:

[I

看起來(lái)數(shù)組的類很奇怪,非但不屬于任何包,而且名稱還不是合法的標(biāo)識(shí)符(identifier)。具體的命名規(guī)則[1]可以參見(jiàn)java.lang.Class.getName()的javadoc。簡(jiǎn)單的說(shuō),數(shù)組的類名由若干個(gè)'['和數(shù)組元素類型的內(nèi)部名稱組成,'['的數(shù)目代表了數(shù)組的維度。

具有相同類型元素和相同維度的數(shù)組,屬于同一個(gè)類。如果兩個(gè)數(shù)組的元素類型相同,但維度不同,那么它們也屬于不同的類。如果兩個(gè)數(shù)組的元素類型和維度均相同,但長(zhǎng)度不同,那么它們還是屬于同一個(gè)類。

數(shù)組的類有哪些成員呢?

既然我們知道了數(shù)組的類名是什么,那么就去看看數(shù)組的類究竟是什么樣的吧?有哪些成員變量?有哪些成員方法?length這個(gè)成員變量在哪?是不是沒(méi)有l(wèi)ength()這個(gè)成員方法?

找來(lái)找去,在JDK的代碼中沒(méi)有找打'[I'這個(gè)類。想想也對(duì),'[I'都不是一個(gè)合法的標(biāo)識(shí)符,肯定不會(huì)出現(xiàn)public class [I {...}這樣的Java代碼。我們暫且不管[I類是誰(shuí)聲明的,怎么聲明的,先用反射機(jī)制一探究竟吧。

  1. public class Main {   
  2. public static void main(String[] args) {   
  3. int a[] = new int[10]; 
  4. Class clazz = a.getClass();   
  5. System.out.println(clazz.getDeclaredFields().length);   
  6. System.out.println(clazz.getDeclaredMethods().length);   
  7. System.out.println(clazz.getDeclaredConstructors().length);   
  8. System.out.println(clazz.getDeclaredAnnotations().length);   
  9. System.out.println(clazz.getDeclaredClasses().length);   
  10. System.out.println(clazz.getSuperclass());   
  11. }   
  12. }  
  13.  

在SUN JDK 1.6上運(yùn)行上述代碼,輸出為:

  1. 0 
  2. 0 
  3. 0 
  4. 0 
  5. 0 
  6. class java.lang.Object  
  7.  

可見(jiàn),[I這個(gè)類是java.lang.Object的直接子類,自身沒(méi)有聲明任何成員變量、成員方法、構(gòu)造函數(shù)和Annotation,可以說(shuō),[I就是個(gè)空類。我們立馬可以想到一個(gè)問(wèn)題:怎么連length這個(gè)成員變量都沒(méi)有呢?如果真的沒(méi)有,編譯器怎么不報(bào)語(yǔ)法錯(cuò)呢?想必編譯器對(duì)Array.length進(jìn)行了特殊處理哇!

數(shù)組的類在哪里聲明的?

先不管為什么沒(méi)有l(wèi)ength成員變量,我們先搞清楚[I這個(gè)類是哪里聲明的吧。既然[I都不是合法的標(biāo)識(shí)符,那么這個(gè)類肯定在Java代碼中顯式聲明的。想來(lái)想去,只能是JVM自己在運(yùn)行時(shí)生成的了。JVM生成類還是一件很容易的事情,甚至無(wú)需生成字節(jié)碼,直接在方法區(qū)中創(chuàng)建類型數(shù)據(jù),就差不多完工了。

還沒(méi)有實(shí)力去看JVM的源代碼,于是翻了翻The JavaTM Virtual Machine Specification  Second Edition,果然得到了驗(yàn)證,相關(guān)內(nèi)容參考5.3.3 Creating Array Classes。

規(guī)范的描述很嚴(yán)謹(jǐn),還摻雜了定義類加載器和初始化類加載器的內(nèi)容。先不管這些,簡(jiǎn)單概括一下:

類加載器先看看數(shù)組類是否已經(jīng)被創(chuàng)建了。如果沒(méi)有,那就說(shuō)明需要?jiǎng)?chuàng)建數(shù)組類;如果有,那就無(wú)需創(chuàng)建了。

如果數(shù)組元素是引用類型,那么類加載器首先去加載數(shù)組元素的類。

JVM根據(jù)元素類型和維度,創(chuàng)建相應(yīng)的數(shù)組類。

呵呵,果然是JVM這家伙自個(gè)偷偷創(chuàng)建了[I類。JVM不把數(shù)組類放到任何包中,也不給他們起個(gè)合法的標(biāo)識(shí)符名稱,估計(jì)是為了避免和JDK、第三方及用戶自定義的類發(fā)生沖突吧。

再想想,JVM也必須動(dòng)態(tài)生成數(shù)組類,因?yàn)镴ava數(shù)組類的數(shù)量與元素類型、維度(最多255)有關(guān),相當(dāng)相當(dāng)多了,是沒(méi)法預(yù)先聲明好的。

居然沒(méi)有l(wèi)ength這個(gè)成員變量!

我們已經(jīng)發(fā)現(xiàn),偷懶的JVM沒(méi)有為數(shù)組類生成length這個(gè)成員變量,那么Array.length這樣的語(yǔ)法如何通過(guò)編譯,如何執(zhí)行的呢?

讓我們看看字節(jié)碼吧!編寫一段最簡(jiǎn)單的代碼,使用jclasslib查看字節(jié)碼。

  1. public class Main {   
  2. public static void main(String[] args)   
  3. int a[] = new int[2]; int i = a.length;   
  4. }   
  5. }  
  6.  

使用SUN JDK 1.6編譯上述代碼,并使用jclasslib打開(kāi)Main.class文件,得到main方法的字節(jié)碼:

  1. 0 iconst_2                   //將int型常量2壓入操作數(shù)棧  
  2. 1 newarray 10 (int)    //將2彈出操作數(shù)棧,作為長(zhǎng)度,創(chuàng)建一個(gè)元素類型為int, 維度為1的數(shù)組,并將數(shù)組的引用壓入操作數(shù)棧  
  3. 3 astore_1                 //將數(shù)組的引用從操作數(shù)棧中彈出,保存在索引為1的局部變量(即a)中  
  4. 4 aload_1                  //將索引為1的局部變量(即a)壓入操作數(shù)棧  
  5. 5 arraylength            //從操作數(shù)棧彈出數(shù)組引用(即a),并獲取其長(zhǎng)度(JVM負(fù)責(zé)實(shí)現(xiàn)如何獲取),并將長(zhǎng)度壓入操作數(shù)棧  
  6. 6 istore_2                 //將數(shù)組長(zhǎng)度從操作數(shù)棧彈出,保存在索引為2的局部變量(即i)中  
  7. 7 return                    //main方法返回  
  8.  

可見(jiàn),在這段字節(jié)碼中,根本就沒(méi)有看見(jiàn)length這個(gè)成員變量,獲取數(shù)組長(zhǎng)度是由一條特定的指令arraylength實(shí)現(xiàn)(怎么實(shí)現(xiàn)就不管了,JVM總有辦法)。編譯器對(duì)Array.length這樣的語(yǔ)法做了特殊處理,直接編譯成了arraylength指令。另外,JVM創(chuàng)建數(shù)組類,應(yīng)該就是由newarray這條指令觸發(fā)的了。

很自然地想到,編譯器也可以對(duì)Array.length()這樣的語(yǔ)法做特殊處理,直接編譯成arraylength指令。這樣的話,我們就可以使用方法調(diào)用的風(fēng)格獲取數(shù)組的長(zhǎng)度了,這樣看起來(lái)貌似也更加OO一點(diǎn)。那為什么不使用Array.length()的語(yǔ)法呢?也許是開(kāi)發(fā)Java的那幫天才對(duì).length有所偏愛(ài),或者拋硬幣拍腦袋隨便決定的吧。 形式不重要,重要的是我們明白了背后的機(jī)理。

Array in Java

最后,對(duì)Java中純對(duì)象的數(shù)組發(fā)表點(diǎn)感想吧。

 

相比C/C++中的數(shù)組,Java數(shù)組在安全性要好很多。C/C++常遇到的緩存區(qū)溢出或數(shù)組訪問(wèn)越界的問(wèn)題,在Java中不再存在。因?yàn)镴ava使用特定的指令訪問(wèn)數(shù)組的元素,這些指令都會(huì)對(duì)數(shù)組的長(zhǎng)度進(jìn)行檢查。如果發(fā)現(xiàn)越界,就會(huì)拋出java.lang.ArrayIndexOutOfBoundsException。

 

Java數(shù)組元素的靈活性比較大。一個(gè)數(shù)組的元素本身也可以是數(shù)組,只要所有元素的數(shù)組類型相同即可。我們知道數(shù)組的類型和長(zhǎng)度無(wú)關(guān),因此元素可以是長(zhǎng)度不同的數(shù)組。這樣,Java的多維數(shù)組就不一定是規(guī)規(guī)矩矩的矩陣了,可以千變?nèi)f化。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
java提高篇(十八)-----數(shù)組之一:認(rèn)識(shí)JAVA數(shù)組
JVM
Java知識(shí)體系冷門篇
深入理解JVM內(nèi)幕:從基本結(jié)構(gòu)到Java 7新特性
Java 虛擬機(jī)體系結(jié)構(gòu)
Java內(nèi)存分配、管理小結(jié)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服