10.java数组

数组介绍

数组是一种用于存储多个相同类型元素的数据结构。每个元素在数组中都有一个唯一的索引,通过索引可以访问和操作数组中的元素。以下是关于数组的详细概念:

  1. 相同类型元素:

    • 数组中的元素必须是相同的数据类型。这意味着可以创建存储整数、浮点数、字符等相同类型的数组,但不能混合不同类型的元素。
  2. 有序集合:

    • 数组是有序的集合,每个元素都有一个位置(索引)来标识其在数组中的位置。索引从0开始递增,依次对应数组中的元素。
  3. 连续的内存空间:

    • 数组的元素在内存中是连续存储的,这使得通过索引快速访问元素成为可能。这也有助于提高访问效率。
  4. 固定大小:

    • 数组的大小在创建时确定,并且通常是固定的。在Java中,数组的大小是不可变的,一旦确定就不能更改。这区别于某些编程语言中的动态数组。
  5. 索引范围:

    • 索引范围从0到数组长度减1,即合法的索引范围是 [0, 数组长度 - 1]
  6. 数组的长度:

    • 数组的长度是指数组中包含的元素的数量。可以使用数组的 length 属性来获取数组的长度。
  7. 多维数组:

    • 数组不仅可以是一维的,还可以是多维的。例如,二维数组可以看作是一个数组的数组,用行和列的索引来访问元素。
  8. 零基索引:

    • 大多数编程语言中,数组的索引是从零开始的。这意味着第一个元素的索引是0,第二个元素的索引是1,以此类推。
  9. 动态数组:

    • 在某些编程语言中,数组的大小是固定的,无法更改。在Java中,可以使用集合类实现动态数组,允许根据需要动态调整数组的大小。

当我们讨论一维数组时,可以将其形象地表示为一排按顺序排列的元素。以下是一个简单的文字图示例:

+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+
| 10| 20| 30| 40| 50|
+---+---+---+---+---+

在这个示例中:

  • 数组的长度为5,有5个元素。
  • 每个元素有一个索引,从0到4。
  • 元素的值分别是10、20、30、40、50。

对于二维数组,可以将其视为一个表格,其中有行和列。以下是一个简单的文字图示例:

+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 7 | 8 | 9 |
+---+---+---+

在这个示例中:

  • 数组的大小是3x3,有3行和3列。
  • 每个元素有两个索引,一个表示行,一个表示列。
  • 元素的值分别是1、2、3、4、5、6、7、8、9。

这些文字图示例有助于形象地理解数组的结构和索引的概念。

数组的声明和初始化

在Java中,数组的声明和初始化可以分为两个步骤:声明数组和创建数组。以下是数组的声明和初始化的基本语法:

1. 数组的声明:

数组的声明指定了数组的类型和名称,但并未分配内存空间。声明的语法如下:

dataType[] arrayName;

其中,dataType 是数组中元素的数据类型,arrayName 是数组的名称。

2. 数组的创建和初始化:

创建数组分配了实际的内存空间,并初始化了数组元素的默认值。数组的创建和初始化的语法如下:

arrayName = new dataType[arraySize];

其中,arraySize 是数组的大小,表示数组可以存储的元素个数。这一步会将数组中的元素初始化为其数据类型的默认值。

合并声明和初始化:

在Java中,可以合并数组的声明和初始化成一步,如下所示:

dataType[] arrayName = new dataType[arraySize];

这种方式更为常见和简便。

方式

在Java中,数组的声明和初始化有几种方式,具体取决于情况和编码偏好。以下是一些常见的方式:

1. 直接声明并初始化:

// 整型数组,直接声明并初始化
int[] numbers = {1, 2, 3, 4, 5};

// 字符数组,直接声明并初始化
char[] vowels = {'a', 'e', 'i', 'o', 'u'};

这种方式将声明和初始化结合在一起,适用于已知数组元素的情况。

2. 分开声明和初始化:

// 整型数组,分开声明和初始化
int[] numbers;
numbers = new int[]{1, 2, 3, 4, 5};

// 字符数组,分开声明和初始化
char[] vowels;
vowels = new char[]{'a', 'e', 'i', 'o', 'u'};

这种方式可以在两个不同的语句中进行声明和初始化,适用于需要分开进行的情况。

3. 简化的声明和初始化(仅适用于局部变量):

// 整型数组,简化声明和初始化(仅适用于局部变量)
int[] numbers = new int[]{1, 2, 3, 4, 5};

// 字符数组,简化声明和初始化(仅适用于局部变量)
char[] vowels = new char[]{'a', 'e', 'i', 'o', 'u'};

在局部变量的情况下,可以进一步简化声明和初始化的方式。

4. 动态初始化:

// 动态初始化整型数组
int[] numbers = new int[5];

// 动态初始化字符数组
char[] vowels = new char[5];

这种方式是在声明数组时只指定大小,而不提供具体的元素值。数组的元素将会根据数据类型的默认值进行初始化。

示例:

以下是一些具体的示例:

1. 整型数组的声明和初始化:
// 声明整型数组
int[] numbers;

// 创建并初始化整型数组,大小为5
numbers = new int[5];

// 或者合并声明和初始化
int[] numbers = new int[5];
2. 字符数组的声明和初始化:
// 声明字符数组
char[] characters;

// 创建并初始化字符数组,大小为3
characters = new char[3];

// 或者合并声明和初始化
char[] characters = new char[3];
3. 字符串数组的声明和初始化:
// 声明字符串数组
String[] names;

// 创建并初始化字符串数组,大小为4
names = new String[4];

// 或者合并声明和初始化
String[] names = new String[4];

这些示例演示了数组的声明和初始化的基本语法,可以根据具体的需求调整数组的数据类型和大小。

数组元素的访问

在Java中,可以使用数组的索引来访问数组元素。数组的索引从0开始,依次递增。以下是数组元素的访问方式:

通过索引访问元素:

// 声明并初始化整型数组
int[] numbers = {10, 20, 30, 40, 50};

// 访问数组中的第三个元素(索引为2)
int thirdElement = numbers[2];
System.out.println("Third element: " + thirdElement);

在这个示例中,通过 numbers[2] 来访问数组中的第三个元素(索引为2),然后将其打印输出。

修改数组元素的值:

// 声明并初始化字符数组
char[] vowels = {'a', 'e', 'i', 'o', 'u'};

// 修改数组中的第一个元素(索引为0)
vowels[0] = 'A';
System.out.println("Modified first element: " + vowels[0]);

在这个示例中,通过 vowels[0] 来访问数组中的第一个元素(索引为0),然后将其修改为大写字母 ‘A’。

使用循环遍历数组元素:

// 声明并初始化整型数组
int[] numbers = {10, 20, 30, 40, 50};

// 使用循环遍历数组并打印每个元素
for (int i = 0; i < numbers.length; i++) {
    System.out.println("Element at index " + i + ": " + numbers[i]);
}

在这个示例中,使用 for 循环遍历整型数组 numbers 中的每个元素,并打印其值和索引。

注意事项:

  1. 数组的索引范围是 [0, 数组长度 - 1]
  2. 尝试访问超出索引范围的元素将导致 ArrayIndexOutOfBoundsException 异常。
  3. 在遍历数组时,确保循环的条件不超过数组的长度,以防止越界。

通过索引访问和修改数组元素是处理数组数据的基本操作,这些操作使得可以有效地操作和管理数组中的元素。

数组内存示意图

java虚拟机内存

Java虚拟机(JVM)在运行Java程序时会对内存进行划分,主要分为以下几个区域:

  1. 程序计数器(Program Counter Register):

    • 程序计数器是一块较小的内存区域,它存储当前线程正在执行的字节码指令的地址。
    • 在多线程环境下,每个线程都有一个独立的程序计数器。
  2. Java虚拟机栈(Java Virtual Machine Stacks):

    • 每个线程在运行时都有一个独立的Java虚拟机栈。
    • 每个方法在执行时都会创建一个栈帧,栈帧包含了局部变量表、操作数栈、动态链接、方法出口等信息。
    • 栈帧随着方法的调用和返回而入栈和出栈。
  3. 本地方法栈(Native Method Stack):

    • 本地方法栈与Java虚拟机栈类似,但它用于执行Native方法,即使用非Java语言编写的方法。
  4. Java堆(Java Heap):

    • Java堆是Java虚拟机管理的最大的一块内存区域,用于存储对象实例。
    • 所有线程共享Java堆,而且在堆中进行垃圾回收。
    • Java堆可以分为新生代(Young Generation)和老年代(Old Generation)。
  5. 方法区(Method Area):

    • 方法区用于存储类的结构信息,如类的代码、静态变量、常量等。
    • 在Java 8及之前,常量池也位于方法区,用于存储编译期生成的各种字面量和符号引用。
    • 从Java 8开始,常量池被移至堆中的“运行时常量池”。
  6. 运行时常量池(Runtime Constant Pool):

    • 运行时常量池是方法区的一部分,用于存储编译时生成的各种字面量和符号引用。
    • 与Class文件中的常量池不同,运行时常量池具有动态性,可以在运行时进行扩展。
  7. 直接内存(Direct Memory):

    • 直接内存并不是JVM规范中定义的内存区域,但在一些实现中有额外的内存区域用于NIO(New I/O)等操作。
    • 直接内存是通过ByteBuffer等类使用Native方法分配的内存,不受Java堆大小的限制,但属于本地内存。

简单的Java虚拟机内存划分图:

--------------------------------
|       程序计数器 (PC)         |
--------------------------------
|     Java虚拟机栈 (Thread 1)   |
--------------------------------
|     Java虚拟机栈 (Thread 2)   |
--------------------------------
|    本地方法栈 (Native Stack)  |
--------------------------------
|         Java堆 (Heap)         |
|      -----------------       |
|      |  新生代 (Young) |       |
|      -----------------       |
|      |  老年代 (Old)   |       |
|      -----------------       |
--------------------------------
|         方法区 (Method Area)  |
--------------------------------
| 运行时常量池 (Runtime CP)    |
--------------------------------
|      直接内存 (Direct Memory)  |
--------------------------------

这个简图展示了Java虚拟机内存的基本划分,包括程序计数器、Java虚拟机栈、本地方法栈、Java堆(分为新生代和老年代)、方法区、运行时常量池以及直接内存。每个线程都有自己的Java虚拟机栈,而Java堆和方法区是所有线程共享的。运行时常量池是方法区的一部分。请注意,这只是一个概念图,实际实现可能有一些细微的差异。

数组在内存中的储存

在这个简图中,我将说明方法栈和堆内存是如何存储一个整型数组的。

假设有以下代码:

public class ArrayExample {
    public static void main(String[] args) {
        int[] arr = new int[5];
        arr[0] = 10;
        arr[1] = 20;
    }
}

简图描述:

----------------------------------------------
|            方法栈 (main 方法)                  |
----------------------------------------------
|           局部变量 arr 引用                    |
|  ----------------------------                |
|  |      堆内存中的数组      |     	           |
|  |  ----------------------  |                |
|  |  |  arr[0]  |  arr[1]  |  |               |
|  |  ----------------------  |                |
|  |  |    10    |    20    |  |               |
|  |  ----------------------  |                |
|  ----------------------------                |
|                                              |
|                                              |
|                                              |
|                                              |
|            实际内存中的数组                     |
|  ----------------------------                |
|  |  arr[0]  |  arr[1]  |  arr[2]  |  arr[3]  | 
|  ----------------------------                |
|  |    10    |    20    |    0     |      0   |
|  ----------------------------                |
----------------------------------------------

解释:

  • 方法栈: 在方法栈中,main 方法被调用,一个名为 arr 的局部变量被创建,并存储了对堆内存中数组的引用。

  • 堆内存: 使用 new int[5] 创建了一个包含5个整数的数组对象。在堆内存中,这个数组的每个元素占据一段空间,而 arr 存储了对数组对象的引用。

  • 数组元素: 数组的前两个元素被赋值为 10 和 20。

请注意,这个简图仅为概念示意,实际上,Java虚拟机会在堆内存中为数组分配一块连续的内存空间,并在方法栈中保存对数组对象的引用。整个过程包括方法栈、堆内存和数组元素的交互。

联系

以下是一些关于数组的练习题及其答案:

练习题 1:

题目: 找到整数数组中的最大值和最小值。

答案:

public class FindMinMax {
    public static void main(String[] args) {
        int[] numbers = {5, 3, 9, 1, 7};
        int min = findMin(numbers);
        int max = findMax(numbers);

        System.out.println("最小值:" + min);
        System.out.println("最大值:" + max);
    }

    // 找到数组中的最小值
    static int findMin(int[] arr) {
        int min = arr[0];
        for (int num : arr) {
            if (num < min) {
                min = num;
            }
        }
        return min;
    }

    // 找到数组中的最大值
    static int findMax(int[] arr) {
        int max = arr[0];
        for (int num : arr) {
            if (num > max) {
                max = num;
            }
        }
        return max;
    }
}

练习题 2:

题目: 反转整数数组中的元素顺序。

答案:

public class ReverseArray {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};
        reverseArray(numbers);

        System.out.print("反转后的数组:");
        for (int num : numbers) {
            System.out.print(num + " ");
        }
    }

    // 反转数组中的元素顺序
    static void reverseArray(int[] arr) {
        int start = 0;
        int end = arr.length - 1;

        while (start < end) {
            // 交换元素
            int temp = arr[start];
            arr[start] = arr[end];
            arr[end] = temp;

            // 移动指针
            start++;
            end--;
        }
    }
}

练习题 3:

题目: 查找整数数组中的重复元素。

答案:

import java.util.HashSet;
import java.util.Set;

public class FindDuplicates {
    public static void main(String[] args) {
        int[] numbers = {2, 3, 1, 2, 4, 3, 5};
        findDuplicates(numbers);
    }

    // 查找数组中的重复元素
    static void findDuplicates(int[] arr) {
        Set<Integer> set = new HashSet<>();
        Set<Integer> duplicates = new HashSet<>();

        for (int num : arr) {
            if (!set.add(num)) {
                // 如果元素已经存在于set中,说明重复
                duplicates.add(num);
            }
        }

        System.out.println("重复元素:" + duplicates);
    }
}

二维数组

在Java中,二维数组是一种数组的数组。它实际上是一个包含数组元素的数组。以下是关于Java二维数组的一些基本概念和使用方法:

声明和初始化二维数组:

// 声明一个二维整数数组
int[][] matrix;

// 初始化一个3x4的二维数组
matrix = new int[3][4];

// 也可以在声明的同时进行初始化
int[][] anotherMatrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };

访问二维数组元素:

// 访问第二行第三列的元素
int element = matrix[1][2];

遍历二维数组:

for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        // 访问 matrix[i][j],执行操作
        int value = matrix[i][j];
        System.out.print(value + " ");
    }
    System.out.println(); // 在每行结束后换行
}

不规则二维数组:

Java 二维数组可以是不规则的,也就是说每一行的长度可以不同:

int[][] irregularMatrix = {
    {1, 2, 3},
    {4, 5},
    {6, 7, 8, 9}
};

注意事项:

  1. 数组长度: 二维数组的每个子数组可以具有不同的长度。
  2. 索引从0开始: 在Java中,数组的索引是从0开始的。
  3. 数组越界: 访问不存在的索引会导致 ArrayIndexOutOfBoundsException
  4. 多维数组: 除了二维数组,Java还支持多维数组,例如三维数组、四维数组等。

Arrays工具的使用

Java提供了 java.util.Arrays 工具类,它包含了许多用于处理数组的静态方法。以下是一些常用的 Arrays 工具类的方法及其使用:

1. 数组排序:

import java.util.Arrays;

public class ArraySortExample {
    public static void main(String[] args) {
        int[] numbers = {5, 2, 8, 1, 3};
        Arrays.sort(numbers);

        System.out.println("排序后的数组:" + Arrays.toString(numbers));
    }
}

2. 数组搜索:

import java.util.Arrays;

public class ArraySearchExample {
    public static void main(String[] args) {
        int[] numbers = {5, 2, 8, 1, 3};
        int key = 8;
        int index = Arrays.binarySearch(numbers, key);

        if (index >= 0) {
            System.out.println(key + " 在数组中的索引位置:" + index);
        } else {
            System.out.println(key + " 不在数组中");
        }
    }
}

3. 数组填充:

import java.util.Arrays;

public class ArrayFillExample {
    public static void main(String[] args) {
        int[] numbers = new int[5];
        Arrays.fill(numbers, 42);

        System.out.println("填充后的数组:" + Arrays.toString(numbers));
    }
}

4. 数组比较:

import java.util.Arrays;

public class ArrayEqualsExample {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3};
        int[] arr2 = {1, 2, 3};

        boolean areEqual = Arrays.equals(arr1, arr2);
        System.out.println("两个数组是否相等:" + areEqual);
    }
}

5. 数组转换为字符串:

import java.util.Arrays;

public class ArrayToStringExample {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};
        String arrayString = Arrays.toString(numbers);

        System.out.println("数组转换为字符串:" + arrayString);
    }
}

这些都是 Arrays 工具类的一些常见方法。该工具类提供了一系列便捷的方法,使数组操作更加简便。希望这些例子能帮助你更好地理解 Arrays 类的使用。如果有其他问题,请随时提问。

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值