Java核心技术卷I (11版)第三章学习(四)

Java核心技术卷I (11版)第三章学习(四)

数组

声明数组
int[] a = new int[100];  // 声明并初始化一个可以存储100个整数的数组

int[] smallPrimes = {2, 3, 5};

// 匿名数组
new int[] {17, 19, 31};
smallPrimes = new int[] {17, 19, 31};  // 可以使用匿名数组来重新初始化一个数组

// 创建长度为0的数组
new elementType[0];
new elementType[] {};
  1. new int[n]表示创建一个长度为n的数组
  2. 若需要扩展数组的大小,则需要使用另一种数组结构——array list
  3. int[] aint a[]都可以定义一个数组变量
  4. Java中有一种创建数组对象并同时提供初始值的简写形式,即int[] smallPrimes = {2, 3, 5};。这个语法中不需要使用new,也不用指定长度
  5. 匿名数组:会分配一个新数组并填入大括号中的值
  6. 长度为0的数组与null并不相同
    • 长度为0的数组:它实际上是一个已经实例化的数组对象,但是它没有包含任何元素。在许多编程语言中,你可以对其进行操作,比如获取其长度(结果为0)、遍历(实际上不会执行任何操作,因为没有元素)、或者添加元素等。
    • null:在许多编程语言中,null通常表示一个引用变量没有引用任何对象。也就是说,它不是一个已经实例化的对象,而是一个表示“无”或“不存在”的特殊值。当你尝试在一个null引用上执行操作时,比如获取长度或遍历,你通常会得到一个空指针异常(NullPointerException)。
访问数组元素
int[] a = new int[100];
for (int i=0; i<100; i++){
    a[i]=i;
}

String[] str = new String[10];
for (int i = 0; i<10; i++){
    str[i]="";
}

for (int i=0; i<a.length; i++){
    System.out.println(a[i]);
}
  1. 数组元素的下标从0开始
for each 循环
// 打印数组a的每一个元素,一个元素一行
for (int element : a)
    System.out.println(element);

  1. for (variable : collection) statement:它定义一个变量用于暂存集合中的每一个元素,并执行相应的语句
  2. collection必须是一个数组或者是一个实现了Iterable接口的类对象(例如ArrayList
  3. for each循环语句的循环变量variable会遍历数组中的每个元素,而不是下标值
  4. 有更简单的方式可以打印数组中的所有值,即利用Arrays类的toString方法。调用Arrays.toString(a),返回一个包含数组元素的字符串,例如“[2,3,4,6,7,11]”,想要打印只需调用System.out.println(Arrays.toString(a));
数组拷贝
int [] luckNumbers = smallPrimes;  // smallPrimes是被拷贝的数组

int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
  1. Java 允许将一个数组变量拷贝到另一个数组变量,这时两个变量将引用同一个数组
  2. copyOf方法的第二个参数是指新数组的长度,这个方法可以用来增加数组长度。
  3. 如果数组元素是数值型,则额外的元素被赋值为0;如果数组元素时布尔型,则将赋值false
Java数组与堆栈上C++数组的不同
  1. C++数组:
    • 在C++中,数组可以分配在栈上或堆上。
    • 当数组在栈上分配时(例如,int arr[10];),数组的大小是固定的,且数组的生命周期与定义它的作用域相同。栈上数组的效率很高,但它们的大小和生命周期是受限的。
    • 当数组在堆上分配时(例如,通过new int[10]),数组的大小可以在运行时确定,并且数组的生命周期可以通过delete[]操作符手动管理。堆上分配提供了更大的灵活性,但也需要更多的注意来避免内存泄漏和其他问题。
  2. Java数组:
    • 在Java中,所有数组都是在堆上分配的,并且是通过Java的垃圾回收器自动管理的。
    • Java数组的大小是动态的,可以在运行时确定,并且可以通过数组的length属性来查询。
    • Java数组是对象,它们包含了对实际数据元素的引用和一个表示数组长度的属性。这意味着即使数组本身是对象,它的元素也可以是基本类型或对象引用。
    • Java不提供指针算术,因此不能通过类似C++中的指针运算来直接访问数组元素。相反,必须使用数组的索引操作符[]来访问元素。

C++ 数组示例

#include <iostream>

int main() {
    // 在栈上分配数组
    int stackArray[5] = {1, 2, 3, 4, 5};
    std::cout << "Stack array element at index 2: " << stackArray[2] << std::endl;

    // 在堆上分配数组
    int* heapArray = new int[5];
    heapArray[0] = 1;
    heapArray[1] = 2;
    heapArray[2] = 3;
    heapArray[3] = 4;
    heapArray[4] = 5;
    std::cout << "Heap array element at index 2: " << heapArray[2] << std::endl;

    // 释放堆上分配的内存
    delete[] heapArray;

    return 0;
}

在C++中,你可以选择在栈上或堆上分配数组。栈上数组的大小在编译时确定,而堆上数组的大小可以在运行时确定。对于堆上分配的数组,你需要使用new操作符来分配内存,并在不再需要数组时使用delete[]操作符来释放内存。

Java 数组示例

public class ArrayExample {
    public static void main(String[] args) {
        // 在堆上分配数组(Java中唯一的分配方式)
        int[] array = {1, 2, 3, 4, 5};
        System.out.println("Array element at index 2: " + array[2]);

        // 动态地创建和初始化数组
        int[] dynamicArray = new int[5];
        dynamicArray[0] = 1;
        dynamicArray[1] = 2;
        dynamicArray[2] = 3;
        dynamicArray[3] = 4;
        dynamicArray[4] = 5;
        System.out.println("Dynamic array element at index 2: " + dynamicArray[2]);

        // Java的垃圾回收器会自动处理不再使用的数组内存
    }
}

在Java中,所有数组都是在堆上分配的,并且你不需要(也不能)手动管理它们的内存。数组的大小可以在运行时确定,并且Java的垃圾回收器会自动处理不再使用的数组。你不能像在C++中那样进行指针算术来访问数组元素;你必须使用数组的索引操作符[]

在Java中,[]运算符用于访问数组的元素。Java确实在运行时进行了数组的越界检查,如果你尝试访问数组索引超出其实际长度的元素,Java会抛出ArrayIndexOutOfBoundsException

关于指针运算,Java确实不支持传统的C/C++风格的指针运算。在C或C++中,你可以通过指针算术来直接访问数组中的下一个元素,比如a + 1。但在Java中,你不能这样做,因为Java中的数组引用并不是指向数组首元素的指针,而是一个指向数组对象的引用。

java.util.Arrays 类方法概述

java.util.Arrays 类包含了一系列静态方法,用于操作数组(如排序、搜索、复制和填充)。以下是该类中一些常用方法的简要说明:

  1. static String toString(xxx[] a)
    返回一个字符串,表示指定的数组及其元素。数组元素被包含在方括号内,并用逗号分隔。这里的 xxx 是数组元素的类型。

  2. static xxx[] copyOf(xxx[] original, int newLength)
    返回一个新数组,它是原始数组的副本,具有指定的新长度。如果新长度大于原始数组的长度,则新数组超出的部分将被填充为该类型的默认值(如 0 对于整型,false 对于布尔型)。如果新长度小于原始数组的长度,则新数组将仅包含原始数组的前 newLength 个元素。

  3. static xxx[] copyOfRange(xxx[] original, int from, int to)
    返回一个新数组,它是原始数组指定范围的一个副本。新数组包含从索引 from(包含)到索引 to(不包含)的原始数组的元素。原始数组和新数组是独立的,对其中一个数组的修改不会影响另一个数组。如果 fromto 指定的范围超出原始数组的界限,则抛出 ArrayIndexOutOfBoundsException

  4. static void sort(xxx[] a)
    使用优化的快速排序算法对数组进行排序。排序是按元素的自然顺序进行的,或者根据数组元素的类型实现的 Comparable 接口。

  5. static int binarySearch(xxx[] a, xxx key)static int binarySearch(xxx[] a, int fromIndex, int toIndex, xxx key)
    使用二分查找算法在有序数组中搜索指定的键。如果找到键,则返回其在数组中的索引;否则返回一个负值,表示应该插入键的位置的 -insertionPoint - 1。第二个版本允许在数组的指定范围内搜索键。

  6. static void fill(xxx[] a, xxx val)
    将指定的值分配给数组的每个元素。此方法可用于快速初始化或重置数组的内容。

  7. static boolean equals(xxx[] a, xxx[] a2)
    如果两个数组的长度相等,并且它们对应的元素都相等,则返回 true;否则返回 false。此方法可用于比较两个数组的内容是否完全相同。

示例

下面是一个综合示例,演示了如何使用 java.util.Arrays 类中的一些方法:

import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        // 创建一个整型数组
        int[] numbers = {5, 2, 9, 1, 5, 6};
        
        // 使用 toString 方法打印数组内容
        System.out.println("Original array: " + Arrays.toString(numbers));
        
        // 使用 sort 方法对数组进行排序
        Arrays.sort(numbers);
        System.out.println("Sorted array: " + Arrays.toString(numbers));
        
        // 使用 binarySearch 方法查找元素(数组必须已排序)
        int index = Arrays.binarySearch(numbers, 5);
        System.out.println("Index of 5 (first occurrence): " + index);
        
        // 使用 copyOf 方法创建一个新长度的数组副本
        int[] numbersCopy = Arrays.copyOf(numbers, 10);
        System.out.println("Copied array (length 10): " + Arrays.toString(numbersCopy));
        
        // 使用 copyOfRange 方法创建一个指定范围的数组副本
        int[] rangeCopy = Arrays.copyOfRange(numbers, 1, 4);
        System.out.println("Range copy (from index 1 to 3): " + Arrays.toString(rangeCopy));
        
        // 使用 fill 方法填充数组
        Arrays.fill(numbers, 0);
        System.out.println("Filled array with zeros: " + Arrays.toString(numbers));
        
        // 比较两个数组是否相等
        int[] anotherArray = {0, 0, 0, 0, 0, 0};
        boolean areEqual = Arrays.equals(numbers, anotherArray);
        System.out.println("Are the arrays equal? " + areEqual);
    }
}

在这个示例中,我们创建了一个整型数组,并使用 Arrays 类中的不同方法对其进行操作。注意,在使用 binarySearch 方法之前,数组必须是已排序的,否则结果将不可预测。此外,copyOfRange 方法的参数是基于零的索引,并且不包括结束索引所指定的元素。

Java多维数组详解

多维数组,即具有多个维度的数组。在Java中,多维数组实际上是“数组的数组”,即数组的每一个元素本身就是一个数组。最常见的多维数组是二维数组,类似于表格结构,有行和列之分。但实际上,Java支持创建任意维度的数组。

二维数组的声明方式如下:

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

初始化二维数组有两种常见方式:直接指定行数和列数进行默认初始化,或在声明的同时进行显式初始化。例如:

int[][] twoDArray = new int[3][4]; // 创建一个3行4列的二维数组,所有元素默认初始化为0

// 或者在声明的同时进行初始化
int[][] anotherTwoDArray = {
    {1, 2, 3, 4}, 
    {5, 6, 7, 8}, 
    {9, 10, 11, 12}
};

Java还支持不规则二维数组,即每一行的长度可以不同:

int[][] jaggedArray = new int[3][]; 
jaggedArray[0] = new int[2]; 
jaggedArray[1] = new int[3]; 
jaggedArray[2] = new int[4];

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

对于三维及更高维度的数组,声明和初始化方式与二维数组类似,只是增加了额外的维度:

int[][][] threeDArray = new int[2][3][4]; // 创建一个2个3x4的二维数组堆叠起来的三维数组

// 访问三维数组的元素时需要指定三个索引
int value = threeDArray[1][2][3]; // 访问第二个3x4数组的第三行第四列的元素

多维数组的内存布局

在内存中,多维数组实际上是连续存储的。对于二维数组来说,它可以看作是一个“数组的数组”,即第一维(行)的数组元素是指向第二维(列)数组的引用。这种布局方式使得Java能够在内存中高效地存储和访问多维数组的元素。对于更高维度的数组,同样采用类似的布局方式。

笔记目录
Java核心技术卷I (11版)第二章学习
Java核心技术卷I (11版)第三章学习(一)
Java核心技术卷I (11版)第三章学习(二)
Java核心技术卷I (11版)第三章学习(三)

  • 34
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值