Java 基础语法深度剖析 Java 中的数组
Posted 吞吞吐吐大魔王
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 基础语法深度剖析 Java 中的数组相关的知识,希望对你有一定的参考价值。
文章目录
一、数组基本用法
1. 什么是数组
和 C 语言一样,Java 中的数组是一块连续的内存,里面可以存放相同类型的变量。它可以在我们要创建若干相同类型变量时,实行批量创建。
但是 Java 中的数组与 C 语言还是有蛮多不同的地方,接下来让我们先了解数组的创建!
2. 创建数组
在 Java 中数组的创建有三种方式
-
静态初始化
int[] array1 = {1,2,3,4,5};
-
动态初始化
int[] array2 = new int[5]; // 默认元素为0 // 打印结果为:[0, 0, 0, 0, 0]
-
动态初始化
int[] array3 = new int[]{1, 2, 3, 4, 5};
注意事项
- Java 中 [] 符号,可以写在变量名前面(写在后面也行)。而这样我们可以更好的理解,上述数组的类型是
int[]
- 数组类型中的 [] 内不能写数值
- 静态初始化的时候,数组元素个数和初始化数据的格式是一致的
3. 数组的使用
-
和 C 语言一样,Java 中访问数组的某个元素直接使用 [] 获取就行,如
int[] array = {1, 2, 3}; System.out.println(arrary[1]); // 打印结果为:2
注意事项
使用 [] 需要注意,下标范围为[0,length - 1]。如果越界将会出现以下异常
java.lang.ArrayIndexOutOfBoundsException
-
在 Java 中如果要遍历数组的话,有多种方法
- 法一(使用循环语句)
int[] array = {1, 2, 3}; for(int i = 0; i <array.length; i++){ System.out.println(array[i]); }
在 Java 中,如上述代码使用
数组对象.length
就可以得到该数组的长度- 法二(使用增强 for 循环 for-each)
int[] array = {1, 2, 3}; for(int x : array){ System.out.println(x); }
如上述代码,该语句会便利数组 array,并且每次都会将数组的元素保存在变量 x 中
- 法三(使用 Arrays 类中的 toString 方法)
// 使用 Arrays 类前先导入它的包 import java.util.Arrays; public class TestDemo{ public static void main(Strings[] args){ int[] array = {1, 2, 3}; String ret = Arrays.toString(array); System.out.println(ret); } } // 打印结果为:[1, 2, 3]
Arrays 类 中 toString 的功能就是将当前的数组转换成字符串的形式返回,返回值就是字符串
上述遍历方式各有各的特点,至于什么时候用哪一遍历方式,据情况而定
二、数组作为方法的参数
1. 认识 JVM 内存区域划分
我们知道,一个 Java 文件的执行需要先通过编译变成字节码文件,字节码文件再痛过 Java 虚拟机运行
因为字节码文件是被 JVM 转换成平台所能执行的形式所运行的,那么 JVM 到底是怎样的呢?
JVM 本质其实就是一个用 C/C++ 代码实现的软件,它的内存被划分五块为如图所示的样子
那么这里面的各块都分别有啥意义呢?
- 程序计数器:是一个很小的空间,保存下一条执行的指令地址(通俗的来说就是你本来在敲代码,你老妈喊你去吃饭,但你吃完饭后还要回来执行完你没敲完的代码)
- Java 虚拟机栈:这就是我们平常说的栈,它重点是存储局部变量(像上面创建的数组
int[] array = {1, 2, 3}
的存储地址的引用就是保存在这里)- 本地方法栈:本地方法栈与虚拟机栈的作用类似,只不过保存的内容是 Native 方法的局部变量(在有些版本的 JVM 的实现中(例如 HotSpot),本地方法和虚拟机栈是一起的)
- 堆:这就是我们平常说的堆,是 JVM 所管理的最大的内存区,使用 new 创建的对象都是在堆上保存(例如
int[] array = new int[]{1, 2, 3}
)- 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(方法编译出的字节码就是保存在这里)
- 运行时常量池:这个是方法区的一部分(上述未画出),存放字面量(字符串常量)与符号引用(注意:从 JDK 1.8 开始,运行时常量池在堆上)
补充(Native 方法)
JVM 是一个基于 C++ 实现的程序,在 Java 程序执行过程中,本质上也需要调用 C++ 提供的一些函数和操作系统底层进行一些交互。因此在 Java 开发中也会调用到一些 C++ 实现的函数
既然知道了 JVM 的一些知识点,那么我们就可以对我们上述三种创建数组的代码做一个存储区域分析
int[] array1 = {1,2,3,4,5};
int[] array2 = new int[5];
int[] array3 = new int[]{1, 2, 3, 4, 5};
分析结果如图
- 我们知道,array1、array2、array3 是局部变量,所以它们会在栈上开辟一块内存。
- Java 中的数组都属于对象,而对象保存在堆中(对象就是一个实体,比如实际生活中的花草树木,或者上述代码中的
{1, 2, 3, 4, 5}
或者用更加规范的方式 new 出来的对象)- 而保存在堆上的对象又有着自己的内存。上述三个局部变量又是引用变量(即这个变量里面存储的是一个地址),它们将会存储对应将每个对象的元素的首地址
- 按照术语来说,用array1举例就是:array1 就是一个引用,它引用了一个对象(指向一个对象)
2. 数组传参以及被调用的过程
我们直接通过一个图片来感受下面代码中数组传参以及被调用的过程
public static void main(String[] args){
int[] array = {1, 2, 3};
print(array;)
}
public static void print(int[] array){
for(int x : array){
System.out.print(x + " ");
}
}
// 打印结果为:1 2 3
3. 理解引用类型
从上图我们可以知道,参数传数组类型,实参和形参其实都是引用,共同指向同一个对象。
因此如果形参将对象的值改变,那么实参的值也随即改变。可以用一个代码举例
public static void main(String[] args){
int[] array = {10, 20};
System.out.print("交换前:array[0] = " + array[0] + " array[1] =" + array[1]);
System.out.println();
swap(array);
System.out.print("交换后:array[0] = " + array[0] + " array[1] =" + array[1]);
}
public static void print(int[] array){
int tmp = array[0];
array[0] = array[1];
array[1] = tmp;
}
// 结果为:
// 交换前:array[0] = 10 array[1] = 20;
// 交换后:array[0] = 20 array[1] = 10;
为了在理解上更加清晰,我们再举一个例子
public static void main(String[] args){
int[] array1 = {1, 2, 3};
int[] array2 = array1;
}
我们可以说 array2 这个引用指向 array1 这个引用吗?不能!这其实是表述有误!
引用不能说指向引用,引用只能说指向另一个引用所指的对象。故我们应该理解成:array2 这个引用指向了 array1 这个引用所指向的对象
小结
- 引用类型本质上只是存了一个地址
- Java 将数组设定成引用类型,这样后续进行数组参数传参,其实只是将数组的地址传到函数的形参中。这样可以避免对整个数组进行拷贝,减小开销
- Java 中的引用类型有:String、数组、类、接口、枚举、抽象类
4. 认识 null
我们来看一个代码
int[] array = null;
上述代码的意思就是 array 这个引用不指向任何对象。这其实和 C 语言里的空指针类似,当我们不道该数组初始化为多少时,就可以赋值为 null
注意
- null 在 Java 中表示空引用,是一个无效的引用。因此不能对这个内存进行任何读写操作,如果对上述代码进行打印的话,会出现一个
java.lang.NullPointerException
的异常- Java 中并没有约定 null 和 0 号地址的内存有任何联系(这和 C 语言中的指针赋值为 null 就是表示0号地址不同)
三、数组作为方法的返回值
在 C 语言中,数组是不能作为返回值的。但是在 Java中,数组可以作为返回值
public static void main(String[] args){
int[] array = {1, 2, 3};
int[] array1 = func(array);
}
public static int[] func(int[] array){
int[] arr = new int[array.length];
for(int i = 0; i < array.length; i++){
arr[i] = 2 * array[i];
}
return arr;
}
// 上述代码就是创建一个新数组并且将原数组的值扩大一倍存入新数组中
如果大家有兴趣的话可以对上述代码里面的参数进行内存区域的分析,以加深对引用的理解!
注意
数组作为方法的返回值时,返回的是数组的首地址
四、总结
该章主要讲解了 Java 中数组的简单使用,以及作为引用类型传参且被调用时的一个分析。不过 Java 中的数组不仅仅如此,下章将介绍二维数组,并且通过多个数组习题让大家熟练数组的使用!
以上是关于Java 基础语法深度剖析 Java 中的数组的主要内容,如果未能解决你的问题,请参考以下文章