java 数组越界判断和获取数组长度的实现方式
作者:jingxian 发布时间:2023-05-24 07:06:52
标签:java,数组越界,数组长度
1. 背景介绍
java中的数组比c语言中的数组,多了两个很重要的功能
当索引越界时, 会自动抛出ArrayIndexOutOfBoundsException, 避免一错再错
另一个很重要的方法是获取数组长度
这两个功能都不是通过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中的数组和c语言数组差异很大, c语言中的数组更原始,直接和内存对应。而java中的数组类型其实是经过了arrayOopDesc的封装,因而能获得更丰富的信息,做更多语言层面的检查。
java 数组越界问题
Java中数组初始化和OC其实是一样的,分为动态初始化和静态初始化,
动态初始化:指定长度,由系统给出初始化值
静态初始化:给出初始化值,由系统给出长度
在我们使用数组时最容易出现的就是数组越界问题,好了,下面来演示一下
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行
来源:https://blog.csdn.net/weixin_45244678/article/details/109034133


猜你喜欢
- 本篇概览在检测人脸数量、位置、性别、口罩等场景时,可以考虑使用百度开放平台提供的web接口,一个web请求就能完成检测得到结果,本篇记录了从
- Radiobutton是一种单选按钮,是由于RadioGroup管理下的一组按钮,所以一旦其中的一个button选中,再点击,就不能取消,想
- 【前言】AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统
- 昨天给各位总结了本人学习springboot整合mybatis第一阶段的一些学习心得和源码,主要就算是敲了一下SpringBoot的门儿,希
- 这篇文章主要介绍了SpringBoot登录判断代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 一.小伙伴们在做钱包支付中,相信会有个绕不过去的输入支付密码页面。下面小编给个效果图:898342572738938468.png实现的原理
- Java基础 Servlet * 详解 1 概念:Servlet * ,用来监听web容器的一些对象状态的变化,主要是Servle
- 一、在drawable下面添加xml文件rounded_editview.xml<?xml version="1.0&quo
- 前言:想象一下,有一个服务提供个多个客户端调用,但不是所有客户端都需要全部的返回参数:比如商品列表服务返回商品的所有信息,而订单服务调用商品
- Android ActionBarActivity设置全屏无标题的方法总结新建的Activity继承自ActionBarActivity,设
- 首先打开 Visual Studio Installer 可以看到vs2022 只支持安装4.6及以上的版本,如图所示。那么该如何安装4.6
- 最近设计要求要一个圆形进度条渐变的需求:1.画圆形进度条2.解决渐变最终实现效果代码package com.view;import andr
- 在Android开发中,我们经常会遇到这样一种情况:在UI界面上进行某项操作后要执行一段很耗时的代码,比如我们在界面上点击了一个”下载“按钮
- 前言回老家,实在太无聊,于是乎给自己整了一套台式机配置,总价 1W+,本以为机器到位后可以打打游戏,学学技术打发无聊的时光。但是我早已不是从
- 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体
- TCP/IP、UDP、Socket对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。
- Socket,又称为套接字,Socket是计算机网络通信的基本的技术之一。如今大多数基于网络的软件,如浏览器,即时通讯工具甚至是P2P下载都
- 1.DRUID连接池介绍Druid是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面
- start方法和run方法$start()$方法用来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到$cpu$时间片,就
- 一:背景1. 讲故事高级语言玩多了,可能很多人对指针或者汇编都淡忘了,本篇就和大家聊一聊指针,虽然C#中是不提倡使用的,但你能说指针在C#中