java?數(shù)組越界判斷和獲取數(shù)組長(zhǎng)度的實(shí)現(xiàn)方式
1. 背景介紹
java中的數(shù)組比c語(yǔ)言中的數(shù)組,多了兩個(gè)很重要的功能
- 當(dāng)索引越界時(shí), 會(huì)自動(dòng)拋出ArrayIndexOutOfBoundsException, 避免一錯(cuò)再錯(cuò)
- 另一個(gè)很重要的方法是獲取數(shù)組長(zhǎng)度
這兩個(gè)功能都不是通過(guò)java代碼層面實(shí)現(xiàn)的, 而是在jvm中通過(guò)c++來(lái)實(shí)現(xiàn)的. 本文就針對(duì)這連個(gè)點(diǎn)來(lái)一探究竟
2. 原始java代碼
public class TestArrayIndexOutOfBoundsException { public static void main(String[] args) { int[] is = new int[2]; int x = is[5]; System.out.println(x); int len = is.length; System.out.println(len); } }
3. java代碼對(duì)應(yīng)的反編譯字節(jié)碼
0 iconst_2 1 newarray 10 (int) // 創(chuàng)建長(zhǎng)度為2的int型數(shù)組 3 astore_1 // 將數(shù)組is存儲(chǔ)到local stack的slot1中 4 aload_1 // 將數(shù)組is壓入操作數(shù)棧 5 iconst_5 // 將常量5壓入操作數(shù)棧 6 iaload // 這個(gè)指令就是通過(guò)數(shù)組索引獲取元素, is[5] 7 istore_2 8 getstatic #2 <java/lang/System.out> 11 iload_2 12 invokevirtual #3 <java/io/PrintStream.println> 15 aload_1 // 將數(shù)組is壓入操作數(shù)棧 16 arraylength // 獲取is數(shù)組的長(zhǎng)度 17 istore_3 18 getstatic #2 <java/lang/System.out> 21 iload_3 22 invokevirtual #3 <java/io/PrintStream.println> 25 return
4. jvm實(shí)現(xiàn)分析
4.1 獲取數(shù)組長(zhǎng)度arraylength指令核心代碼分析
// hotspot\src\share\vm\interpreter\bytecodeInterpreter.cpp void BytecodeInterpreter::run(interpreterState istate) { // 省略無(wú)關(guān)代碼 CASE(_arraylength): { // java中的對(duì)象實(shí)例, 對(duì)應(yīng)的c++實(shí)例就是arrayOopDesc arrayOop ary = (arrayOop) STACK_OBJECT(-1); CHECK_NULL(ary); SET_STACK_INT(ary->length(), -1); // 就是通過(guò)ary->length()這個(gè)方法來(lái)獲取數(shù)組長(zhǎng)度 UPDATE_PC_AND_CONTINUE(1); } } // 省略無(wú)關(guān)代碼
4.2 獲取數(shù)組元素iaload指令分析
// hotspot\src\share\vm\interpreter\bytecodeInterpreter.cpp void BytecodeInterpreter::run(interpreterState istate) { // 省略無(wú)關(guān)代碼 #define ARRAY_INTRO(arrayOff) \ arrayOop arrObj = (arrayOop)STACK_OBJECT(arrayOff); \ // 從局部變量表中獲取數(shù)組對(duì)象is jint index = STACK_INT(arrayOff + 1); \ // 從局部變量表中獲取索引5 char message[jintAsStringSize]; \ CHECK_NULL(arrObj); \ if ((uint32_t)index >= (uint32_t)arrObj->length()) { \ // 判斷索引是否大于或等于數(shù)組長(zhǎng)度 sprintf(message, "%d", index); \ VM_JAVA_ERROR(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), \ // 如果越界, 則拋出ArrayIndexOutOfBoundsException異常 message); \ } // 省略無(wú)關(guān)代碼 #define ARRAY_LOADTO32(T, T2, format, stackRes, extra) \ { \ ARRAY_INTRO(-2); \ // 獲取數(shù)組所在的地址 (void)extra; \ SET_ ## stackRes(*(T2 *)(((address) arrObj->base(T)) + index * sizeof(T2)), \ // 根據(jù)數(shù)組所在地址,加上索引計(jì)算的偏移地址, 獲得數(shù)組指定元素 -2); \ UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); \ } // 省略無(wú)關(guān)代碼 CASE(_iaload): // 此處對(duì)應(yīng)的就是iaload指令的具體實(shí)現(xiàn) ARRAY_LOADTO32(T_INT, jint, "%d", STACK_INT, 0); } // 省略無(wú)關(guān)代碼
通過(guò)上面代碼的分析, 可以jvm是通過(guò)(uint32_t)index >= (uint32_t)arrObj->length()來(lái)判斷數(shù)組越界
5. 小結(jié)一下
java中的數(shù)組和c語(yǔ)言數(shù)組差異很大, c語(yǔ)言中的數(shù)組更原始,直接和內(nèi)存對(duì)應(yīng)。而java中的數(shù)組類(lèi)型其實(shí)是經(jīng)過(guò)了arrayOopDesc的封裝,因而能獲得更豐富的信息,做更多語(yǔ)言層面的檢查。
java 數(shù)組越界問(wèn)題
Java中數(shù)組初始化和OC其實(shí)是一樣的,分為動(dòng)態(tài)初始化和靜態(tài)初始化,
- 動(dòng)態(tài)初始化:指定長(zhǎng)度,由系統(tǒng)給出初始化值
- 靜態(tài)初始化:給出初始化值,由系統(tǒng)給出長(zhǎng)度
在我們使用數(shù)組時(shí)最容易出現(xiàn)的就是數(shù)組越界問(wèn)題,好了,下面來(lái)演示一下
int [][] array = {{1,2,3},{1,4}}; System.out.println(array[1][2]);
這是一個(gè)二維數(shù)組,很明顯,數(shù)組越界了,控制臺(tái)中會(huì)打印如下信息:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at demo.Array.main(Array.java:31)
很準(zhǔn)確的定位到31行
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于SpringBoot+Avue實(shí)現(xiàn)短信通知功能
Avue是基于vue和element-ui的快速開(kāi)發(fā)框架 ,它的核心是數(shù)據(jù)驅(qū)動(dòng)UI的思想,讓我們從繁瑣的crud開(kāi)發(fā)中解脫出來(lái),本文將給大家介紹一下使用SpringBoot+Avue實(shí)現(xiàn)短信通知功能,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-09-09IntelliJ IDEA版Postman強(qiáng)大功能介紹
這篇文章主要為大家介紹了IDEA版Postman的強(qiáng)大功能介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Java實(shí)現(xiàn)調(diào)用對(duì)方http接口得到返回?cái)?shù)據(jù)
這篇文章主要介紹了Java實(shí)現(xiàn)調(diào)用對(duì)方http接口得到返回?cái)?shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09基于request獲取訪問(wèn)者真實(shí)IP代碼示例
這篇文章主要介紹了基于request獲取訪問(wèn)者真實(shí)IP代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10詳解SpringBoot Redis自適應(yīng)配置(Cluster Standalone Sentinel)
這篇文章主要介紹了詳解SpringBoot Redis自適應(yīng)配置(Cluster Standalone Sentinel),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Java動(dòng)態(tài)獲取實(shí)現(xiàn)某個(gè)接口下所有的實(shí)現(xiàn)類(lèi)對(duì)象集合
今天小編就為大家分享一篇關(guān)于Java動(dòng)態(tài)獲取實(shí)現(xiàn)某個(gè)接口下所有的實(shí)現(xiàn)類(lèi)對(duì)象集合,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12Java異常--常見(jiàn)方法--自定義異常--增強(qiáng)try(try-with-resources)詳解
這篇文章主要介紹了Java異常--常見(jiàn)方法--自定義異常--增強(qiáng)try(try-with-resources)的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03