我是靠谱客的博主 香蕉缘分,这篇文章主要介绍java 数组越界判断和获取数组长度的实现方式,现在分享给大家,希望可以做个参考。

1. 背景介绍

java中的数组比c语言中的数组,多了两个很重要的功能

  • 当索引越界时, 会自动抛出ArrayIndexOutOfBoundsException, 避免一错再错
  • 另一个很重要的方法是获取数组长度

这两个功能都不是通过java代码层面实现的, 而是在jvm中通过c++来实现的. 本文就针对这连个点来一探究竟

2. 原始java代码

复制代码
1
2
3
4
5
6
7
8
9
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代码对应的反编译字节码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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指令核心代码分析

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// hotspotsrcsharevminterpreterbytecodeInterpreter.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指令分析

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// hotspotsrcsharevminterpreterbytecodeInterpreter.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中的数组和c语言数组差异很大, c语言中的数组更原始,直接和内存对应。而java中的数组类型其实是经过了arrayOopDesc的封装,因而能获得更丰富的信息,做更多语言层面的检查。

java 数组越界问题

Java中数组初始化和OC其实是一样的,分为动态初始化和静态初始化,

  • 动态初始化:指定长度,由系统给出初始化值
  • 静态初始化:给出初始化值,由系统给出长度

在我们使用数组时最容易出现的就是数组越界问题,好了,下面来演示一下

复制代码
1
2
int [][] array = {{1,2,3},{1,4}}; System.out.println(array[1][2]);

这是一个二维数组,很明显,数组越界了,控制台中会打印如下信息:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2

at demo.Array.main(Array.java:31)

很准确的定位到31行

以上为个人经验,希望能给大家一个参考,也希望大家多多支持靠谱客。

最后

以上就是香蕉缘分最近收集整理的关于java 数组越界判断和获取数组长度的实现方式的全部内容,更多相关java 数组越界判断和获取数组长度内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(125)

评论列表共有 0 条评论

立即
投稿
返回
顶部