java中实现数组越界判断和获取数组长度的实现1. 背景介绍
java中的数组⽐c语⾔中的数组, 多了两个很重要的功能
1. 当索引越界时, 会⾃动抛出ArrayIndexOutOfBoundsException, 避免⼀错再错
2. 另⼀个很重要的⽅法是获取数组长度
这两个功能都不是通过java代码层⾯实现的, ⽽是在jvm中通过c++来实现的. 本⽂就针对这连个点来⼀探究竟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代码对应的反编译字节码
0 iconst_2
1 newarray 10 (int) // 创建长度为2的int型数组
3 astore_1 // 将数组is存储到local stack的slot1中
4 aload_1 // 将数组is压⼊操作数栈
5 iconst_5 // 将常量5压⼊操作数栈
6 iaload // 这个指令就是通过数组索引获取元素, 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 // 将数组is压⼊操作数栈
16 arraylength // 获取is数组的长度
17 istore_3
18 getstatic #2 <java/lang/System.out>
21 iload_3
22 invokevirtual #3 <java/io/PrintStream.println>
25 return
4. jvm实现分析
4.1 获取数组长度arraylength指令核⼼代码分析
// hotspot\src\share\vm\interpreter\bytecodeInterpreter.cpp
void
BytecodeInterpreter::run(interpreterState istate){
// 省略⽆关代码
CASE(_arraylength):
{
// java中的对象实例, 对应的c++实例就是arrayOopDesc
arrayOop ary =(arrayOop)STACK_OBJECT(-1);
CHECK_NULL(ary);
SET_STACK_INT(ary->length(),-1);// 就是通过ary->length()这个⽅法来获取数组长度
UPDATE_PC_AND_CONTINUE(1);
}
}
// 省略⽆关代码
4.2 获取数组元素iaload指令分析
// hotspot\src\share\vm\interpreter\bytecodeInterpreter.cpp
void
BytecodeInterpreter::run(interpreterState istate){
// 省略⽆关代码
#define ARRAY_INTRO(arrayOff)                                                  \
arrayOop arrObj = (arrayOop)STACK_OBJECT(arrayOff);                      \ // 从局部变量表中获取数组对象is
jint    index  =STACK_INT(arrayOff +1);                              \ // 从局部变量表中获取索引5
char message[jintAsStringSize];                                          \
CHECK_NULL(arrObj);                                                      \
if((uint32_t)index >=(uint32_t)arrObj->length()){                    \ // 判断索引是否⼤于或等于数组长度
sprintf(message,"%d", index);                                      \
VM_JAVA_ERROR(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), \ // 如果越界, 则抛出ArrayIndexOutOfBoundsException异常
message);                                              \
}
// 省略⽆关代码
#define ARRAY_LOADTO32(T, T2, format, stackRes, extra)                                \
{                                                                              \
ARRAY_INTRO(-2);                                                            \ // 获取数组所在的地址
(void)extra;                                                                \
SET_ ## stackRes(*(T2 *)(((address) arrObj->base(T))+ index *sizeof(T2)), \ // 根据数组所在地址,加上索引计算的偏移地址, 获得数组指定元素-2);                                                      \
UPDATE_PC_AND_TOS_AND_CONTINUE(1,-1);                                      \
}
// 省略⽆关代码
CASE(_iaload):// 此处对应的就是iaload指令的具体实现
ARRAY_LOADTO32(T_INT, jint,"%d",  STACK_INT,0);
}
// 省略⽆关代码
通过上⾯代码的分析, 可以jvm是通过(uint32_t)index >= (uint32_t)arrObj->length()来判断数组越界
5. 总结
java中index是什么意思java中的数组和c语⾔数组差异很⼤, c语⾔中的数组更原始, 直接和内存对应. ⽽java中的数组类型其实是经过了arrayOopDesc的封装, 因⽽能获得更丰富的信息, 做更多语⾔层⾯的检查.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。