深入理解 Java 基本语法之数组
目录
一、数组基础概念
二、数组的声明
1. 基本数据类型数组声明:
2. 引用数据类型数组声明:
三、数组的创建
四、数组的初始化
五、数组的使用
编辑1. 获取长度以及访问元素:
2. 数组作为方法的参数:
3. 数组作为方法的返回值:
六、多维数组
1. 二维数组的声明和初始化
2. 调用数组的指定位置的元素
3. 获取数组的长度
4. 遍历二维数组
5. 二维数组元素的默认初始化值
七、Arrays 类
1. 判断两个数组是否相等
2. 输出数组信息
3. 将指定值填充到数组之中
4. 对数组进行排序
5. 对排序后的数组进行二分法检索指定的值
八、数组的常见应用场景 编辑
一、数组基础概念
数组是同一种类型数据的集合,是一种容器,能给存储进来的元素自动进行编号,编号从 0 开始。数组有以下特点:
- 长度确定且不可变。一旦数组被初始化,其长度就不能再改变。例如在 Java 中,定义一个整型数组int[] arr = new int[5];,这个数组的长度就是 5,不能在后续的代码中增加或减少这个数组的长度。
- 元素必须是相同类型。Java 中的数组要求数组中的元素类型统一,不能存储不同类型的元素。例如不能在一个整型数组中存储字符串类型的数据。
- 数组变量属引用类型,数组本身也是对象,在堆中分配空间。Java 语言中的数组是一种引用类型,不属于基本数据类型。数组的父类是 Object。数组实际上是一个容器,可以同时容纳多个元素。数组因为是引用类型,所以数组对象是在堆内存当中。数组当中如果存储的是 “Java 对象” 的话,实际上存储的是对象的 “引用(内存地址)”。
二、数组的声明
数组在 Java 中有多种声明方式,主要分为基本数据类型数组声明和引用数据类型数组声明。
1. 基本数据类型数组声明:
基本数据类型数组可以使用int[] i或int i[]的方式进行声明。例如,声明一个整型数组可以写为int[] numbers或int numbers[]。Java 中更推荐使用int[] numbers这种方式,因为它具有更好的可读性。
2. 引用数据类型数组声明:
引用数据类型数组可以使用Car[] c或Car c[]的方式进行声明,在 Java 中推荐用Car[] c。比如,如果有一个自定义的类Person,声明一个Person类型的数组可以写为Person[] people。引用数据类型的数组在声明后也需要进行初始化才能使用。初始化的方式可以是静态初始化或动态初始化。例如,静态初始化可以这样写:Person[] people = new Person[]{new Person("张三", 1), new Person("李四", 2)};动态初始化可以这样写:Person[] people = new Person[3],然后再通过给每个元素赋值的方式进行初始化,如people[0] = new Person("王五", 3)。
三、数组的创建
数组在 Java 中有多种创建方式,下面分别介绍基本数据类型数组和引用数据类型数组的创建方法。
- 创建基本数据类型数组:可以使用int[] i = new int[2];的方式创建一个整型基本数据类型数组。这种方式在创建时指定了数组的长度为 2,创建后数组中的元素会被初始化为对应类型的默认值,对于整型来说,默认值为 0。
- 创建引用数据类型数组:以Car[] c = new Car[100];为例,可以创建一个引用数据类型数组。假设Car是一个自定义的类,这种方式创建了一个长度为 100 的Car类型数组。创建后,数组中的每个元素初始值为 null,因为引用类型的默认值为 null。
- 数组创建后有初始值,数字类型为 0,布尔类型为 false,引用类型为 null。例如,创建一个byte类型的数组,其元素默认初始值是 0;创建一个float类型的数组,其元素默认初始值是 0.0f;创建一个boolean类型的数组,其元素默认初始值是 false;如果创建一个自定义的引用类型数组,如Person[] people = new Person[3],那么创建后数组中的每个元素初始值为 null。
四、数组的初始化
数组的初始化方式主要有以下几种:
- 初始化、创建、和声明分开:
-
- 首先进行声明:int[] i;
-
- 然后创建数组并指定长度:i = new int[2];
-
- 最后为数组元素赋值:i[0] = 0;,i[1] = 1;。
- 初始化、创建、和声明在同一时间:
- 可以使用int[] i = {0,1};的方式,直接在声明的同时为数组元素分配空间并赋值。
- 也可以使用int[] i = new int[]{1,2,3,4,5};的方式,先使用new关键字创建数组,同时为数组中的元素赋值,这里不需要指定数组的长度,数组长度由其后的初始化操作确定。
数组的初始化方式还包括静态初始化、动态初始化和默认初始化。静态初始化是在定义数组的同时为数组元素分配空间并赋值,由系统决定数组的长度,例如int[] a = {1,2,3}或Man[] mans = {new Man(1, 1), new Man(2, 2)}。动态初始化是在初始化时由程序员指定数组的长度,由系统初始化每个数组元素的默认值,例如int[] a1 = new int[2],然后再给数组元素赋值。默认初始化是对于引用类型的数组,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化,例如int a2[] = new int[2],其默认值为0,0;boolean[] b = new boolean[2],其默认值为false,false;String[] s = new String[2],其默认值为null,null。
注意:不要同时使用静态初始化和动态初始化,一旦数组完成初始化,数组在内存中所占的空间将被固定下来,所以数组的长度将不可改变。
五、数组的使用
1. 获取长度以及访问元素:
在 Java 中,获取数组长度非常简单,可以使用arr.length表示获取数组长度。例如:
int[] numbers = {1, 2, 3, 4, 5};
int length = numbers.length;
System.out.println("数组的长度是: " + length);
访问数组元素可以通过System.out.println(arr[0]);的方式。还可以通过循环语句打印全部元素,如:
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
此外,还有 for-each 遍历数组语句:for(int i : arr){System.out.println(i);},此方法不可以改变数组的值,只是数组的复制值。
2. 数组作为方法的参数:
可以将数组作为方法的参数来打印数组内容。理解引用类型参数传内置类型时,形参的结果不会影响实参值;参数传数组类型时,在函数内部修改数组内容,函数外部也发生改变。例如:
public static void main(String[] args) {
int[] arr = {1, 3, 5};
System.out.println(arr[0]);
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] arr) {
arr[0] = 200;
}
3. 数组作为方法的返回值:
数组也可以作为方法的返回值。比如:
public class Demo02ArrayReturn {
public static void main(String[] args) {
int[] result = calculate(10, 20, 30);
System.out.println("main方法接收到的返回值数组是:");
System.out.println(result); // 地址值
System.out.println("总和:" + result[0]);
System.out.println("平均数:" + result[1]);
}
public static int[] calculate(int a, int b, int c) {
int sum = a + b + c; // 总和
int avg = sum / 3; // 平均数
int[] array = {sum, avg};
System.out.println("calculate方法内部数组是:");
System.out.println(array); // 地址值
return array;
}
}
六、多维数组
1. 二维数组的声明和初始化
- Java 中二维数组可以有多种声明和初始化方式,例如:
-
- int[][] arr1=new int[][]{{1,2,3},{4,5,6}};:这是一种静态初始化的方式,直接在创建数组的同时为其赋值。
-
- String[][] arr2=new String[3][2];:动态初始化,指定了二维数组的外层长度为 3,内层长度为 2,但未为元素赋值。
-
- String[][] arr3=new String[3][];:动态初始化,只指定了外层长度为 3,内层长度未确定。
-
- int[] arr4[]=new int[][]{{1,2,3},{4,5,6}};:另一种声明方式,与第一种类似,也是静态初始化。
-
- int[] arr5[]={{1,2,3},{4,5,6}};(类型推断):简洁的初始化方式,省略了new关键字,但效果与第一种相同。
2. 调用数组的指定位置的元素
- 二维数组的元素可以通过指定行和列的索引来访问。例如,对于二维数组arr,内层元素可以通过arr[行索引][列索引]来访问,如arr[3][2];外层元素可以通过只指定行索引来访问,如arr[3]。
3. 获取数组的长度
- 在二维数组中,可以使用arr.length来获取外层元素的数量,即数组的行数。而要获取某一行(外层元素)的长度(列数),可以使用arr[行索引].length。例如,如果有一个二维数组int[][] arr = {{1,2,3},{4,5,6}};,那么arr.length的值为 2,arr[0].length的值为 3。
4. 遍历二维数组
- 二维数组可以使用嵌套的for循环来遍历。外层for循环遍历外层元素,控制行数;内层for循环遍历内层元素,控制列数。例如:
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
这段代码会依次输出二维数组中的每一个元素,每输出完一行元素后换行。
5. 二维数组元素的默认初始化值
- 对于初始化方式int[][] arr = new int[4][3];,外层元素的初始化值为地址值,内层元素的初始化值与一维数组初始化情况相同。例如,对于整型二维数组,内层元素的初始值为 0。
- 对于初始化方式int[][] arr=new int[4][];,外层元素的初始化值为null,内层元素的初始化值不能调用,否则会报错。例如:
int[][] arr = new int[4][];
System.out.println(arr[0]); // null
// System.out.println(arr[0][0]); // 会报错,空指针异常
七、Arrays 类
Java 中的java.util.Arrays类是操作数组的工具类,包含了用来操作数组的各种方法,如判断两个数组是否相等、输出数组信息、将指定值填充到数组之中、对数组进行排序、对排序后的数组进行二分法检索指定的值。
1. 判断两个数组是否相等
可以使用Arrays.equals(数组1,数组2)方法来判断两个数组是否相等。数组类型必须相等,该方法的返回值为boolean类型。例如:
int[] arr1 = new int[]{1,2,3,4,6};
int[] arr2 = new int[]{1,2,3,4,5};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals);
2. 输出数组信息
使用Arrays.toString(数组名)方法可以输出数组信息。例如:
int[] arr2 = new int[]{1,2,3,4,5};
System.out.println(Arrays.toString(arr2));
3. 将指定值填充到数组之中
Arrays.fill(数组名,填充值)方法可以将指定值填充到数组之中。填充值数据类型应与数组数据类型相同,该方法会把要填充的数组数据全部改为指定值。例如:
int[] arr2 = new int[]{1,2,3,4,5};
Arrays.fill(arr2,9);
System.out.println(Arrays.toString(arr2));
4. 对数组进行排序
使用Arrays.sort(数组名)方法可以对数组进行排序。例如:
int[] arr2 = new int[]{5,4,1,2,3};
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));
5. 对排序后的数组进行二分法检索指定的值
使用Arrays.binarySearch(数组名,查询值)方法可以对排序后的数组进行二分法检索指定的值。使用前提是当前数组必须是有序的,返回值为int,为负则查找失败,找到了返回下标。例如:
int[] arr1 = new int[]{1,2,3,4,6};
int index = Arrays.binarySearch(arr1,1);
System.out.println(index);
八、数组的常见应用场景
数组在实际编程中有很多常见的应用场景,其中之一就是存储一组数据进行统计分析,如计算平均值、最大值、最小值等。
例如,可以使用以下方法获取数组中的最大值和最小值:
方法一:该方法使用交换顺序来寻找最大值,但查找完以后会污染数组,不能同时运行寻最大值方法和最小值方法。
/*获取数组里的最大值和最小值*/
public class TestFindArrayNum {
public static void main(String[] args) {
int[] arr = {500,11,12,100,11,13,1,3,5,205,7,9,2,4,6,8,400,0,300,10};
findMaxNum(arr);
//使用寻找最小值方法之前要先注释掉寻找最大值的方法
//因为使用完寻找最大值的方法后会污染数组,整个数组都会变为最大值500
//findMinNum(arr);
}
private static void findMaxNum(int[] arr) {
int maxNum = 0;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] > arr[i]) {
maxNum = arr[i + 1];
} else {
arr[i + 1] = arr[i];
maxNum = arr[i];
}
}
System.out.println("数组中最大值是" + maxNum);
}
private static void findMinNum(int[] arr) {
int minNum = 0;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] < arr[i]) {
minNum = arr[i + 1];
} else {
arr[i + 1] = arr[i];
minNum = arr[i];
}
}
System.out.println("数组中最小值是" + minNum);
}
}
方法二:方法二代码更加简洁且不会污染数组
/*获取数组里的最大值和最小值*/
public class TestFindArrayNum2 {
public static void main(String[] args) {
int[] arr = {500,11,12,100,11,13,1,3,5,205,7,9,2,4,6,8,400,0,300,10};
findMaxNum(arr);
findMinNum(arr);
}
private static void findMaxNum(int[] arr) {
int max = arr[0];
for (int i = 1; i <= arr.length - 1; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
System.out.println("数组中最大值" + max);
}
private static void findMinNum(int[] arr) {
int min = arr[0];
for (int i = 1; i <= arr.length - 1; i++) {
if (min > arr[i]) {
min = arr[i];
}
}
System.out.println("数组中最小值" + min);
}
}
方法三:
public class TestFindArrayNum3 {
private int max;
private int min;
public int getMax() {
return max;
}
public int getMin() {
return min;
}
public void FindMaxAndMin(int[] arr ) {
if(arr==null){
System.out.println("输入的数组为空");
return;
}
int i = 0;
int len = arr.length;
max = arr[0];
min = arr[0];
//两两分组,把较小的数挪到左边,较大的数挪到右边
for(i = 0; i < len - 1; i += 2){
if(arr[i]>arr[i + 1]){
int tmp = arr[i];
arr[i]= arr[i + 1];
arr[i + 1]= tmp;
}
}
//最小值放在各个分组的左边
min = arr[0];
for(i = 2; i < len ; i += 2){
if(arr[i]<min){
min = arr[i];
}
}
//最大值放在各个分组的右边
max = arr[1];
for(i = 3; i < len; i += 2){
if(arr[i]>max){
max = arr[i];
}
}
//如果数组中元素个数是奇数个,最后一个元素被分为一组,需要特殊处理
if(len%2==1){
if(max<arr[len - 1])
max = arr[len - 2];
if(min>arr[len - 1])
min = arr[len - 1];
}
}
public static void main(String[] args) {
int[] arr={500,11,12,100,11,13,1,3,5,205,7,9,2,4,6,8,400,0,300,10};
TestFindArrayNum3 f =new TestFindArrayNum3();
f.FindMaxAndMin(arr);
System.out.println("最大值是"+f.getMax());
System.out.println("最小值是"+f.getMin());
}
}
除了获取最大值和最小值,还可以计算数组的平均值。一般情况下对数组计算均值,可以采用对数组求和,再除以数组长度。实现代码:
public double doubleArrAverage(double[] arr) {
double sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum / arr.length;
}
但其中存在最大问题就是数组求和,如果数组内元素值较大或者数组元素非常多,很有可能出现内存溢出。解决这种问题,一种方法是采用每个元素除以数组长度,再对结果求和。实现代码:
public double doubleArrage(double[] arr) {
double result = 0;
for (int i = 0; i < arr.length; i++) {
result += arr[i] / arr.length;
}
return result;
}
另一种方法是,假定数组长度是动态的,当存在一个元素时,均值ave即为当前数组值arr[0]。当加入第二个个元素,第二个元素减去均值ave,得到的差值除以数组长度,再与均值ave相加,即可得到数组均值。以此类推,直到数组所有元素参与计算,也就完成了整个数组均值计算。实现代码:
public double doubleArrage(double[] arr) {
double result = arr[0];
for (int i = 1; i < arr.length; i++) {
double temp = arr[i];
result += (temp - result) / (i + 1);
}
return result;
}
在实际编程中,数组还可以用于对用户输入的成绩进行排序和计算平均分。例如:
Scanner scanner = new Scanner(System.in);
int[] scores = new int[5];
for (int i = 0; i < scores.length; i++) {
scores[i] = scanner.nextInt();
}
Arrays.sort(scores);
double average = Arrays.stream(scores).average().orElse(Double.NaN);
这段代码演示了如何使用数组来收集用户输入的成绩,对这些成绩进行排序,并计算平均值。
数组的常见应用场景还包括排序算法教学、搜索引擎索引、股票市场分析等。在排序算法教学中,可以使用数组来展示冒泡排序、选择排序等算法;在搜索引擎索引中,可以使用数组作为倒排索引的一部分,快速检索关键词;在股票市场分析中,可以使用数组存储股票价格,分析市场趋势。