《Java教程系列》一: Java 中的数组
Java 中的数组是最基本的数据结构之一,它允许我们在单个变量中存储相同类型的多个值。它们对于存储和管理数据集合非常有用。Java 中的数组是对象,这使得它们在内存管理方面与 C/C++ 中的数组不同 。对于基元数组 , 元素存储在连续的内存位置,对于非基元数组 , 引用存储在连续的位置,但实际对象可能位于内存中的不同位置。
数组的主要特点:
- 连续内存分配(对于基元):Java 数组元素存储在连续的内存位置,这意味着这些元素在内存中彼此相邻放置。
- 从零开始的索引: 数组的第一个元素位于索引 0 处。
- 固定长度: 数组创建后,其大小是固定的,无法更改。
- 可以存储原始类型和对象:Java 数组可以容纳原始类型(如 int、char、boolean 等)和对象(如 String、Integer 等)。
示例: 此示例演示如何初始化数组并使用 for 循环遍历它以打印每个元素。
public class Main {
public static void main(String[] args)
{
// initializing array
int[] arr = { 1, 2, 3, 4, 5 };
// size of array
int n = arr.length;
// traversing array
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
}
}
输出
1 2 3 4 5
Java 中的数组基础
我们可以从一些基本作开始,如下所述:
1. 数组声明
要在 Java 中声明数组,请使用以下语法:
type[] 数组名称;
- type:数组元素的数据类型(例如
int
、String
)。 - arrayName:数组的名称。
注意: 数组尚未初始化。
2. 创建数组
要创建数组,您需要使用 new
关键字为其分配内存 :
创建一个包含 5 个整数的数组
int[] 数字 = new int[5];
此语句初始化 numbers
数组以保存 5 个整数。每个元素的默认值为 0
。
3. 访问数组的元素
我们可以使用数组元素的索引来访问数组元素,索引从 0
开始 :
设置数组的第一个元素
数字[0] = 10;访问第一个元素
int firstElement = 数字[0];
第一行将第一个元素的值设置为 10
。第二行检索第一个元素的值。
4. 更改数组元素
要更改元素,请为特定索引分配新值:
将第一个元素更改为 20
数字[0] = 20;
5. 数组长度
我们可以使用 length
属性获取数组的长度 :
获取数组的长度
int 长度 = 数字.length;
现在,我们已经完成了基本作,所以让我们通过图表、示例和解释来深入了解 Java 数组的概念 。
Java Array 的深入概念
以下是有关 Java 数组的一些要点。
数组属性
- 在 Java 中,所有数组都是动态分配的 。
- 数组可以存储在连续的内存 [连续内存位置] 中。
- 由于数组在 Java 中是对象,我们可以使用 object 属性 length 来找到它们的长度 。这与 C/C++ 不同,在 C/ 中,我们使用 size of 来查找长度。
- Java 数组变量也可以像其他变量一样在数据类型后使用 [] 声明。
- 数组中的变量是有序的,每个变量都有一个从 0 开始的索引。
- Java 数组还可以用作静态字段、局部变量或方法参数。
数组可以包含类的基元 (int、char 等) 和 object (或非基元) 引用,具体取决于数组的定义。对于原始数据类型,实际值可能存储在连续的内存位置(JVM 不保证此行为)。对于类对象, 实际对象存储在堆段中 。
注意: 数组的这种存储可以帮助我们随机访问数组的元素 [支持随机访问]。
在 Java 中创建 、初始化和访问数组
为了理解数组,我们需要了解它的实际工作原理。要理解这一点,请遵循下面提到的流程:
- 宣
- 初始化
- 访问
1. 声明一个数组
数组声明的一般形式是
方法 1:
键入 var-name[];方法 2:
type[] var-name;
元素类型确定组成数组的每个元素的数据类型。就像一个整数数组一样,我们也可以创建一个其他原始数据类型的数组,如 char、float、double 等,或者用户定义的数据类型(类的对象)。
注意: 这只是我们如何创建一个数组变量, 不存在实际的数组 。它只是告诉编译器这个变量 (int Array) 将保存一个整数类型的数组。
现在,让我们为这个创建的数组提供内存存储。
2. 在 Java 中初始化数组
声明数组时,仅创建数组的引用。new 适用于一维数组的一般形式如下所示:
var-name = 新类型 [size];
在这里,type 指定要分配的数据类型,size 确定数组中的元素数,var-name 是链接到数组的数组变量的名称。要使用 new 分配数组, 必须指定要分配的元素的类型和数量。
例:
声明数组
int intArray[];将内存分配给数组
intArray = 新 int[20];将两个语句合二为一
int[] intArray = 新 int[20];
注意: 由 new 分配的数组中的元素 将自动初始化为零 (对于数字类型)、false(对于布尔值)或 null(对于引用类型)。请参阅 Java 中的默认数组值 。
获取数组的过程分为两个步骤。首先,您必须声明所需数组类型的变量。其次,您必须使用 new 分配内存来保存数组,并将其分配给数组变量。因此, 在 Java 中 , 所有数组都是动态分配的。
Java 中的数组文本
在数组的大小和数组的变量已知的情况下,可以使用数组文本。
声明数组文本
int[] intArray = 新 int[]{ 1,2,3,4,5,6,7,8,9,10 };
- 此数组的长度决定了创建的数组的长度。
- 在最新版本的 Java 中,无需编写新的 int[] 部分。
3. 使用 for 循环访问 Java 数组元素
现在,我们已经创建了一个 Array,其中包含或不具有其中存储的值。Access 成为使用下面提到的点对数组索引中提到的值进行作的重要部分:
- 数组中的每个元素都通过其索引进行访问。
- 索引从 0 开始,到 (total array size)-1 结束。
- array 的所有元素都可以使用 Java for Loop 访问。
让我们检查一下遍历数组的基本 for 循环的语法 :
访问指定数组的元素
对于 (int i = 0; i < arr.length; i++)
System.out.println(“索引处的元素” + i + “ : ”+ arr[i]);
实现:
// Java program to illustrate creating an array
// of integers, puts some values in the array,
// and prints each value to standard output.
class GFG {
public static void main(String[] args)
{
// declares an Array of integers.
int[] arr;
// allocating memory for 5 integers.
arr = new int[5];
// initialize the elements of the array
// first to last(fifth) element
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
// accessing the elements of the specified array
for (int i = 0; i < arr.length; i++)
System.out.println("Element at index "
+ i + " : " + arr[i]);
}
}
输出
Element at index 0 : 10
Element at index 1 : 20
Element at index 2 : 30
Element at index 3 : 40
Element at index 4 : 50
Java 中的数组类型
Java 支持不同类型的数组:
1. 一维数组
这些是最常见的数组类型,其中元素按线性顺序存储。
一维数组
int[] singleDimArray = {1, 2, 3, 4, 5};
2. 多维数组
具有多个维度的数组,例如二维数组(矩阵)。
一个 2D 数组(矩阵)
int[][] multiDimArray = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9} };
您还可以使用 for each 循环访问 java 数组 。
Java 中的对象数组
对象数组的创建方式与基元类型数据项的数组类似。
语法:
方法 1:
ObjectType[] arrName;方法 2:
ObjectType arrName[];
对象数组示例
示例:这里我们采用一个 Student 类并创建一个 Student 数组,数组中存储了 5 个 Student 对象。Student 对象必须使用 Student 类的构造函数进行实例化,并且它们的引用应该分配给数组元素。
// Java program to illustrate creating
// an array of objects
class Student {
public int roll_no;
public String name;
Student(int roll_no, String name){
this.roll_no = roll_no;
this.name = name;
}
}
public class Main {
public static void main(String[] args){
// declares an Array of Student
Student[] arr;
// allocating memory for 5 objects of type Student.
arr = new Student[5];
// initialize the elements of the array
arr[0] = new Student(1, "aman");
arr[1] = new Student(2, "vaibhav");
arr[2] = new Student(3, "shikar");
arr[3] = new Student(4, "dharmesh");
arr[4] = new Student(5, "mohit");
// accessing the elements of the specified array
for (int i = 0; i < arr.length; i++)
System.out.println("Element at " + i + " : { "
+ arr[i].roll_no + " "
+ arr[i].name+" }");
}
}
输出
Element at 0 : { 1 aman }
Element at 1 : { 2 vaibhav }
Element at 2 : { 3 shikar }
Element at 3 : { 4 dharmesh }
Element at 4 : { 5 mohit }
示例: 还会创建一个对象数组,例如
// Java program to illustrate creating
// an array of objects
class Student{
public String name;
Student(String name){
this.name = name;
}
@Override
public String toString(){
return name;
}
}
public class Main{
public static void main (String[] args){
// declares an Array and initializing the
// elements of the array
Student[] myStudents = new Student[]{
new Student("Dharma"),new Student("sanvi"),
new Student("Rupa"),new Student("Ajay")
};
// accessing the elements of the specified array
for(Student m:myStudents){
System.out.println(m);
}
}
}
输出
Dharma
sanvi
Rupa
Ajay
如果我们尝试访问数组大小之外的元素会发生什么?
JVM 抛出 ArrayIndexOutOfBoundsException 以指示该数组已被非法索引访问。索引为负数,或者大于或等于数组的大小。
下面的代码显示了如果我们尝试访问数组大小之外的元素会发生什么:
// Code for showing error "ArrayIndexOutOfBoundsException"
public class GFG {
public static void main(String[] args)
{
int[] arr = new int[4];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
System.out.println(
"Trying to access element outside the size of array");
System.out.println(arr[5]);
}
}
输出
Trying to access element outside the size of array
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 4
at GFG.main(GFG.java:13)
Java 中的多维数组
多维数组是数组的数组 ,数组的每个元素都包含其他数组的引用。通过为每个维度附加一组方括号 ([]) 来创建多维数组。
语法:
有 2 种方法可以声明 Java 多维数组,如下所述:
方法 1
数据类型 [][] arrayref 变量;方法 2
数据类型 arrayrefvariable[][];
声明:
2D 数组或矩阵
int[][] intArray = 新 int[10][20];3D 阵列
int[][][] intArray = new int[10][20][10];
Java 多维数组示例
示例: 让我们从声明和初始化的基本二维 Array 开始。
// Java Program to demonstrate
// Multidimensional Array
import java.io.*;
class GFG {
public static void main(String[] args){
// Two Dimensional Array
// Declared and Initialized
int[][] arr = new int[3][3];
// Number of Rows
System.out.println("Rows : " + arr.length);
// Number of Columns
System.out.println("Columns : " + arr[0].length);
}
}
输出
Rows:3
Columns:3
示例: 现在,在声明和初始化数组之后,我们将检查如何使用 for 循环遍历多维数组。
// Java Program to Multidimensional Array
// Driver Class
public class multiDimensional {
// main function
public static void main(String args[])
{
// declaring and initializing 2D array
int arr[][] = { { 2, 7, 9 }, { 3, 6, 1 }, { 7, 4, 2 } };
// printing 2D array
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
System.out.print(arr[i][j] + " ");
System.out.println();
}
}
}
输出
2 7 9
3 6 1
7 4 2
将数组传递给方法
像变量一样,我们也可以将数组传递给方法。例如,下面的程序将数组传递给方法 sum 以计算数组值的总和。
// Java program to demonstrate
// passing of array to method
public class Test {
// Driver method
public static void main(String args[])
{
int arr[] = { 3, 1, 2, 5, 4 };
// passing array to method m1
sum(arr);
}
public static void sum(int[] arr)
{
// getting sum of array values
int sum = 0;
for (int i = 0; i < arr.length; i++)
sum += arr[i];
System.out.println("sum of array values : " + sum);
}
}
输出
sum of array values : 15
从方法返回数组
像往常一样,一个 method 也可以返回一个数组。例如,下面的程序从方法 m1 返回一个数组 。
// Java program to demonstrate
// return of array from method
class Test {
// Driver method
public static void main(String args[])
{
int arr[] = m1();
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
}
public static int[] m1()
{
// returning array
return new int[] { 1, 2, 3 };
}
}
输出
1 2 3
Java 数组成员
现在,如你所知,数组是类的对象,数组的直接超类是类 Object。
数组类型的成员是以下所有成员:
- public final field length 包含数组的组件数。Length 可以是正数或零。
- 所有成员都是从类 Object 继承的;Object 中唯一未继承的方法是其 clone 方法。
- 公共方法 clone() 覆盖类 Object 中的 clone 方法,并且不会引发检查异常 。
数组类型及其允许的元素类型
数组类型 | 允许的元素类型 |
---|---|
基元类型数组 | 任何可以隐式提升为声明类型的类型。 |
对象类型数组 | 声明的类型对象或它的子类对象。 |
抽象类类型数组 | 允许其 child-class 对象。 |
接口类型数组 | 允许其实现类对象。 |
在 Java 中克隆数组
1. 一维数组的克隆
当您克隆一维数组(如 Object[])
时 , 将执行浅表复制 。这意味着新数组包含对原始数组元素的引用,而不是对象本身的副本。深层复制仅发生在包含原始数据类型的数组中,其中将复制实际值。
下面是上述方法的实现:
// Java program to demonstrate
// cloning of one-dimensional arrays
class Test {
public static void main(String args[])
{
int intArray[] = { 1, 2, 3 };
int cloneArray[] = intArray.clone();
// will print false as shallow copy is created
System.out.println(intArray == cloneArray);
for (int i = 0; i < cloneArray.length; i++) {
System.out.print(cloneArray[i] + " ");
}
}
}
输出
false
1 2 3
2. 克隆多维数组
然而,多维数组的克隆(如 Object[][])是一个“浅拷贝”,也就是说它只创建一个新数组,每个元素数组都是对原始元素数组的引用,但子数组是共享的。
下面是上述方法的实现:
// Java program to demonstrate
// cloning of multi-dimensional arrays
class Test {
public static void main(String args[])
{
int intArray[][] = { { 1, 2, 3 }, { 4, 5 } };
int cloneArray[][] = intArray.clone();
// will print false
System.out.println(intArray == cloneArray);
// will print true as shallow copy is created
// i.e. sub-arrays are shared
System.out.println(intArray[0] == cloneArray[0]);
System.out.println(intArray[1] == cloneArray[1]);
}
}
输出
false
true
true
常见作
下表演示了常见的数组作
操作 |
例 |
---|---|
排序 |
数组.sort(arr); |
搜索 |
Arrays.binarySearch(arr, 键); |
复制 |
int[] 复制 = Arrays.copyOf(arr, len); |
填补 |
数组.child(arr, 0); |
Java 数组的优点
- 高效访问 :通过索引访问元素的速度很快,并且具有恒定的时间复杂度 O(1)。
- 内存管理 :数组具有固定大小,这使得内存管理简单明了且可预测。
- 数据组织 :数组有助于以结构化方式组织数据,从而更轻松地管理相关元素。
Java 数组的缺点
- 固定大小 :创建数组后,无法更改其大小,如果大小高估,则可能导致内存浪费,如果大小被低估,则可能导致存储空间不足。
- 类型同质性 :数组只能存储相同数据类型的元素,这可能需要对混合类型的数据进行额外处理。
- 插入和删除 :插入或删除元素,尤其是在数组的中间,可能成本高昂,因为它可能需要移动元素。
要避免的常见错误
下面列出了在 Java 中使用数组时可能发生的常见错误:
- 访问越界索引: 当我们尝试访问数组范围之外的索引(即负索引或大于或等于数组长度的索引)时,它将抛出索引 ArrayIndexOutOfBoundsException。始终确保索引在边界内,该边界应介于 0 和 array.length - 1 之间。
- 假设数组大小可以更改:Java 数组的大小是固定的。尝试更改数组的大小(如添加或删除元素)是不可能的。
- 不初始化数组元素:如果我们创建一个数组但没有显式初始化其元素,Java 将根据类型自动分配默认值
- 对于数值类型(例如 int、double): 默认值为 0。
- 对于布尔数组: 默认值为 false。
- 对于对象数组: 默认值为 null。
最佳实践
下面列出了在 Java 中使用数组时的最佳实践:
- 尽可能使用 for-each 循环(避免索引错误): for-each 循环是迭代数组元素的最佳方式,而无需担心索引越界错误 。它降低了访问无效索引的风险。
- 在访问元素之前检查数组长度: 在尝试访问元素之前 ,始终使用 array.length 检查数组的长度 。这有助于防止 ArrayIndexOutOfBoundsException。
- 使用 Arrays.copyOf() 而不是手动复制: 如果您需要复制数组,请使用 Arrays.copyOf() 而不是使用循环手动复制每个元素。
- 如果需要动态调整大小 , 则首选 ArrayList: 如果您需要可以动态调整大小(添加或删除元素)的集合,请考虑使用 ArrayList 而不是数组。