2.5数组

在 Java 里,数组属于一种数据结构,它能够存储固定数量的相同类型元素。

数组在编程中是一种非常基础且重要的数据结构,它被广泛使用是因为能带来诸多便利

1. 数据集中管理

当你需要处理多个相同类型的数据时,数组能够把这些数据集中存储。比如,要记录一个班级 50 个学生的考试成绩,若不使用数组,就需要为每个成绩单独创建一个变量,这会使代码变得冗长且难以管理。而使用数组,仅需一个数组变量就能存储所有成绩,示例代码如下:

// 创建一个能存储 50 个成绩的数组
double[] scores = new double[50];

2. 方便数据访问

数组中的元素可以通过索引快速访问。索引是一个整数,代表元素在数组中的位置,从 0 开始计数。这种特性使得程序能够直接定位到所需的数据,极大地提高了数据访问的效率。例如,要获取上述班级中第 10 个学生的成绩,只需通过索引操作即可:

// 获取第 10 个学生的成绩
double tenthScore = scores[9]; 

3. 便于数据处理和算法实现

很多算法和数据处理操作都是基于数组来实现的。例如,排序算法(如冒泡排序、快速排序)、搜索算法(如线性搜索、二分搜索)等,这些算法在数组上能够高效地运行。

4. 内存连续性

在大多数编程语言中,数组在内存中是连续存储的。这意味着数组中的元素在内存中是一个接一个排列的,这种存储方式使得计算机能够更高效地访问数组元素,因为它可以利用 CPU 的缓存机制,减少内存访问的时间开销。

5. 支持多维数据表示

数组可以扩展为多维数组,用于表示更复杂的数据结构,如矩阵、表格等。例如,在图像处理中,可以使用二维数组来表示图像的像素矩阵;在游戏开发中,可以使用三维数组来表示三维空间中的物体位置

数组的使用

1. 数组的声明

数组声明时需要明确元素的类型和数组名称,格式如下:

// 声明一维数组
dataType[] arrayName;
// 或者
dataType arrayName[];

// 示例
int[] numbers;
String names[];

2. 数组的初始化

数组初始化可以采用静态初始化或者动态初始化。

静态初始化

在创建数组时就为其赋值,格式如下:

dataType[] arrayName = {value1, value2, ..., valueN};

// 示例
int[] numbers = {1, 2, 3, 4, 5};
String[] names = {"Alice", "Bob", "Charlie"};
动态初始化

先创建数组,之后再为其元素赋值,格式如下:

dataType[] arrayName = new dataType[arraySize];

// 示例
// 此时 会对 数组中的元素初始化,里边存的是int的默认值:0
int[] numbers = new int[5];
// 为元素赋值
numbers[0] = 1;
numbers[1] = 2;

3. 数组的访问

数组元素可通过索引来访问,索引从 0 开始。

int[] numbers = {1, 2, 3, 4, 5};
// 访问第一个元素
int firstNumber = numbers[0]; 
System.out.println(firstNumber); // 输出 1

4. 数组的遍历

length 是数组的一个属性,用于获取数组的长度。数组的 length 属性是一个final类型的常量,这意味着你无法直接修改它。一旦数组被创建,其长度就固定了,不能再改变

在for遍历数组时,length 属性十分有用,它能确保循环访问到数组的每个元素,同时避免越界访问。

使用 for 循环
int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}
使用 for-each 循环
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    System.out.println(number);
}

5. 多维数组

多维数组就是数组的数组,常见的有二维数组。

多维数组的 length 属性

对于多维数组,length 属性返回的是数组第一维的长度。如果要获取其他维度的长度,需要对相应的子数组使用 length 属性。

二维数组的声明和初始化
// 静态初始化
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// 动态初始化
int[][] matrix2 = new int[3][3];
matrix2[0][0] = 1;
matrix2[0][1] = 2;
// 依此类推
二维数组的遍历
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}

6. 数组的常用方法

Java 提供了一些实用的数组方法,例如 Arrays 类中的方法。

import java.util.Arrays;

public class ArrayExample {
    public static void main(String[] args) {
        int[] numbers = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
        //​​​(值复制)
        int[] deepCopy = Arrays.copyOf(numbers, numbers.length);
        // 对数组进行排序
        Arrays.sort(numbers); 
        System.out.println(Arrays.toString(numbers));
        System.out.println(Arrays.toString(deepCopy));
        // 查找元素
        int index = Arrays.binarySearch(numbers, 5);
        System.out.println("元素 5 的索引是: " + index);
    }
}

7. 数组是引用类型

在 Java 里,内存主要分为堆内存和栈内存。
栈内存

栈内存用于存储局部变量和方法调用信息。当你声明一个数组变量时,这个变量就会被存储在栈内存中,不过它仅仅是一个引用,并非实际的数组对象。

堆内存

堆内存用于存储对象实例。当你使用 new 关键字创建一个数组时,实际的数组对象会被分配到堆内存中,而栈内存中的引用变量则指向这个堆内存中的数组对象

数组作为引用类型的特性
  1. ​引用传递案例​

    • ​方法内修改数组元素​
      public class Test {
          public static void main(String[] args) {
              int[] a = {1, 2, 3};
              fun(a); // 传递引用
              System.out.println("a[0] = " + a[0]); // 输出25
          }
          public static void fun(int[] b) {
              b[0] = 25; // 修改原数组
          }
      }
      ​解析​​:ab指向同一内存地址,修改b即修改a
  2. ​数组赋值与引用​

    int[] arr1 = {1, 2, 3};
    int[] arr2 = arr1; // arr2引用arr1的地址
    arr2[0] = 100; // arr1[0]同步变为100
  3. 多态性​​:数组可指向子类对象(需父类引用子类实例)
    Number[] nums = new Integer[3]; // 允许
  • package com.example.demo1;
    
    public class Test1 {
        public static Object arr[];
        public static void main(String[] args) {
            arr = new Integer[3]; // 允许;
            arr[0] = 1;
            arr[1] = 2;
            arr[2] = 3;
    
            Integer tmp[] =  (Integer[])(arr);
            for (int index = 0; index < arr.length; index++) {
                
                    System.out.println(tmp[index]);
                
            }
        }
    }
    


常见问题与注意事项

  1. ​空指针异常(NullPointerException)​

    int[] arr = null;
    System.out.println(arr[0]); // 抛出异常
  2. ​数组越界(ArrayIndexOutOfBoundsException)​

    int[] arr = {1, 2, 3};
    System.out.println(arr[3]); // 索引范围0-2
  3. 数组是对象,存储在堆内存中,变量名是引用,拷贝数组需使用Arrays.copyOf() ,避免直接赋值导致引用共享

  4. ​默认值规则​

综合案例,评委打分

            int len = 6;
            // 定义一个包含 6 个评委打分的数组
            int[] scores = new int[len];
            Random r = new Random();
            for (int i = 0; i < scores.length; i++) {
                scores[i] = r.nextInt(10,100);
            }
            
            // 初始化最高分和最低分
            int max = scores[0];
            int min = scores[0];
            int sum = 0;
    
            // 遍历数组,找出最高分、最低分并求和
            for (int score : scores) {
                if (score > max) {
                    max = score;
                }
                if (score < min) {
                    min = score;
                }
                sum += score;
            }
    
            // 去掉最高分和最低分后的总分
            int finalSum = sum - max - min;
    
            // 计算平均分. 整数操作会去掉小数部分。所以,除之前,先变成浮点数,在操作
            double average = (double)finalSum  / (scores.length - 2);
            // double average = finalSum * 1.0 / (scores.length - 2);
    
            System.out.println("各位评委打分结果: " + Arrays.toString(scores));
            System.out.printf("去掉最高分%d和最低分%d后的平均分是%.2f: " ,max,min,average);
       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chxii

小小打赏,大大鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值