Java 数组

一、数组的基本概念

1、什么是数组

    数组是相同类型元素的集合。创建数组的时候,Java就会再内存中分配一段连续的空间来存放数组的内容。每一个数组内容都有自己的编号,这个编号从0开始的,也就是数组的下标从0开始。通过数组的下标来访问数组的内容。

2、一维数组的创建和初始化

创建一个数组:

T[] 数组名 = new T[N];

T:数组中元素的类型。

T[]:表示是数组类型,[]也可以放在数组名的后面。这里的[]不能有任何的数组

N:创建数组要的长度。 

比如:

int[] array1 = new int[10]; // 创建一个可以容纳10个int类型元素的数组
double[] array2 = new double[5]; // 创建一个可以容纳5个double类型元素的数组
String[] array3 = new double[3]; // 创建一个可以容纳3个字符串元素的数组

要对数组进行初始化,有两种方式。

静态初始化:知道数组的内容,就可以静态初始化。

int[] arr = { 1,2,3,4 }; //省略情况
int[] arr = new int[] { 1,2,3,4 };//可以省略new int[]

上面两种初始化的方式是没有区别的。

如果不知道数组的内容,那么就可以使用动态初始化。

int[] arr = new int[10]; //定义10个int类型的数组

上面两种创建方式都可以分两步进行创建:

int[] array1;
array1 = new int[10];
int[] array2;
array2 = new int[]{10, 20, 30};
// 注意省略格式不可以拆分, 否则编译失败
// int[] array3;
// array3 = {1, 2, 3};

    如果没有对数组进行初始化,数组中的元素有默认值。不同的数据类型有不同的默认值,如果是简单类型,大多是默认值为0。float是0.0f,double是0.0,char是/u0000,boolean是false;引用类型比如字符串类型则是null。

二、一维数组的使用

1、数组元素的访问

数组在内存中是一段连续的空间,下标是从0开始的。比如:

int[]array = new int[]{10, 20, 30, 40, 50};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
System.out.println(array[4]);

当然,我们可以对数组的内容进行修改。将上面的array[0]改为20:

array[0] = 20;
System.out.println(array[0]);

在Java中,数组[]里面的大小支持常量,变量和表达式。

这在C语言中,C99之前是不行的。 

    数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素。数组的下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。

int[] array = {1, 2, 3};
System.out.println(array[3]); // 数组中只有3个元素,下标一次为:0 1 2,array[3]下标越界

    上面的结果报出了一个数组越界的异常。当下标是3的时候,说明越界了。这样的错误发生在main函数的第12行。通过这个,可以很快的找到问题的所在。

2、数组的遍历

在Java中,对数组的遍历有两种方式:第一种是for,第二种是增强for(foreach)。

    由于Java是面向对象的语言,在Java中,一切都是对象,比如数组。数组这个对象有它的属性,比如数组的长度等,基于这一点,我们可以不用刻意知道数组的长度,使用.length来获取数组的长度。

//for
int[]array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < array.length; i++){
    System.out.println(array[i]);
}
//foreach
int[] array = {1, 2, 3};
for (int x : array) {
System.out.println(x);
}
//说明:
//int x :array
//数组中的数据类型+变量名,这里array数组里面的类型是int
//array是数组名
//foreach
double[] array = {1.0, 2.0, 3.0};
for (double x : array) {
System.out.println(x);
}

增强for循环是得不到数组的下标的,所以它一般用于数组的遍历,比如数组累加这样的操作。

三、数组在内存中的分布

1、JVM内存分布简介

    要了解数组在内存里面的情况,就要知道Java内存分布是什么样的,这里做必要的介绍。Java经过编译后产生的.class文件被加载到JVM虚拟机里面的本地方法栈里面运行。为了高效管理内存,JVM对内存进行了划分。JVM是一个软件,由C/C++编写的软件。这是因为系统之类的由C/C++代码编写比较高效。

 说明:

(1)Java虚拟机栈:也是我们在Java中常说栈。一般用来存放局部变量。

(2)本地方法栈:运行由c/c++编写的代码。经过编译产生的.class文件被加载到这里运行。

(3)堆:是Java中最大的一块内存空间。只要是对象,都是在堆上开辟的。在堆里面的引用叫对象。堆上的内存是不需要进行手动释放的,Java有自己的垃圾回收机制。

(4)程序计数器:保存一些指令和信息等。

(5)方法区:存放常量,静态成员变量等。

这里重点关心堆和虚拟机栈。

2、引用类型变量

    引用类型创建的变量,一般称为对象的引用。存储的是对象所在空间的地址。如何理解数组的引用呢?比如写了这么一个代码:

int[] arr = new int[] {1,2,3};

在内存中发生了什么呢?

    这里的arr是局部变量,运行代码后,java就会在栈上为arr分配空间。后面new了之后,就会在堆上开辟一块空间来保存这些内容。arr存的是后面对象的地址。这里要强调的是,引用变量存的是对象的地址。

现在我们直接打印arr看看:

    打印出了这么一个地址(可以理解为数组首元素地址)。这里的地址为了安全,经过了特殊的处理,是这个引用对象的哈希地址。@之后的是哈希地址,@前的I表示这是一个int型,[表示是一个数组。arr这个引用,引用(指向)了一个数组对象。在比如以下代码:

int[] arr = new int[] { 1,2,3,4 };
int[] brr = arr;//???
System.out.println(arr);
System.out.println(brr);

这里打印出来的地址是一样的,说明brr也引用了与arr相同的对象。

现在我们打印出这两个数组的内容看看:

在brr里面修改brr[0]的值:

    要注意这里的brr=arr,是把arr的值给了brr。arr引用了这个对象,brr引用了arr引用的对象,而不是brr指向arr(换句话来说,就是引用指向引用)。

那么要注意的几点:

(1)引用不能指向引用,引用指向了对象(引用的对象)。

(2)一个引用,不能同时引用多个对象。

这里的arr引用新的对象的时候,没有同时引用。

(3)引用不一定在栈上。还有可能在堆上,比如成员变量。

(4)引用赋值为null表示不指向任何对象。

3、例题

public static void fun1(int[] array) {
    array = new int[] { 5,6,7,8 };

}

public static void fun2(int[] array) {
    array[0] = 2;
}

public static void main(String[] args) {

    int[] arr = new int[] { 1,2,3,4 };
    fun1(arr);
    System.out.println(Arrays.toString(arr));
    int[] brr = new int[] { 1,1,1,1 };
    fun2(arr);
    System.out.println(Arrays.toString(arr));
}

分别打印出来的结果是?

第一个的图示:

第二个和之前的是相同的。

四、二维数组

1、二维数组定义

二维数组本质上也就是一维数组,只不过每个元素又是一个一维数组。

数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };

int[][] arr1 = { {1,2,3},{4,5,6} };
int[][] arr2 = new int[][] { {1,2,3},{4,5,6} };
int[][] arr3 = new int[2][3];
int[][] arr4 = new int[2][];

    在Java中,如果是前两种定义的方式,必须要手动加括号。同时,行是必须要指定的,列可以不用指定。

2、二维数组遍历

和一维数组类似,二维数组有for循环和foreach循环来进行遍历。

int[][] arr1 = { {1,2,3},{4,5,6} };
//for
for (int i = 0; i < arr1.length; i++) {
    for (int j = 0; j < arr1[i].length; j++) {

         System.out.print(arr1[i][j] + " ");
     }
     System.out.println();
}

//foreach
for (int[] x : arr1) {
    for (int y : x) {
        System.out.print(y + " ");
    }
    System.out.println();
}

五、数组常用的方法

    Java中的Arrays工具类包括了数组常用的一些方法,比如数组的排序,数组的拷贝等方法,而这些方法,在我们的日常生活中也是经常使用的。在使用之前需要导入:import java.util.Arrays;

    这些方法是重构的,这里拿int类型的数组简单介绍一下,其他的原理是相同的。具体的内容见官方文档。

1、Arrays.toString方法

将一维数组变成字符串。二维数组使用Arrays.deepToString方法。

public static String toString(int[] a)

参数

a - 要返回其字符串表示形式的数组

public static void main(String[] args) {
    int[] array = new int[] { 1,2,3,4 };
    System.out.println(Arrays.toString(array));//[1,2,3,4]
}

2.1、Arrays.copfOf方法

从0下标来时复制指定长度数组的内容到新的数组中。

public static int[] copyOf(int[] original, int newLength)

参数

original - 要复制的数组

newLength - 要返回的副本的长度

public static void main(String[] args) {
    int[] array = new int[] { 1,2,3,4 };
    int[] ret = Arrays.copyOf(array,2);
    System.out.println(Arrays.toString(ret));//[1,2]
}

2.2、Arrays.copyOfRange方法

和Arrays.copfOf方法类似,这个是指定范围的拷贝。范围是左闭右开区间。

public static int[] copyOfRange(int[] original, int from, int to)

参数

original - 要从中复制范围的数组

from - 要复制的范围的初始索引(包括)

to - 要复制的范围的最终索引,除了它本身。 (该索引可能位于数组之外)

public static void main(String[] args) {
    int[] array = new int[] { 1,2,3,4 };
    int[] ret = Arrays.copyOfRange(array,2,4);
    System.out.println(Arrays.toString(ret));//[3,4]
}

3、Arrays.sort方法

对数组进行升序排序。

public static void sort(int[] a)

public static void main(String[] args) {
    int[] array = new int[] { 4,3,2,1 };
    Arrays.sort(array);
    System.out.println(Arrays.toString(array));//[1,2,3,4]
}

4、Arrays.fill方法

对数组内容进行指定填充。

public static void fill(int[] a, int val)//全部填充

参数

a - 要填充的数组

val - 要存储在数组的所有元素中的值

public static void fill(int[] a, int fromIndex, int toIndex, int val)//指定范围填充

参数

a - 要填充的数组

fromIndex - 要用指定值填充的第一个元素(包括)的索引

toIndex - 要用指定值填充的最后一个元素(排除)的索引

val - 要存储在数组的所有元素中的值

public static void main(String[] args) {
    int[] array = new int[10];
    Arrays.fill(array,10);
    Arrays.fill(array,2,8,20);
    System.out.println(Arrays.toString(array));
}

 5、Arrays.equal方法

判断两个数组的内容是否相同

public static boolean equals(int[] a, int[] a2)

参数

a - 要测试相等的一个数组

a2 - 要测试的其他数组是否相等

public static void main(String[] args) {
    int[] arr1 = new int[] { 4,3,2,1 };
    int[] arr2 = new int[] { 1,2,3,4 };
    int[] arr3 = new int[] { 1,2,3,4 };
    System.out.println(Arrays.equals(arr1, arr2));//false
    System.out.println(Arrays.equals(arr2, arr3));//true
}

 6、Arrays.binarySearch方法

二分查找数组内容,使用前先sort排序数组。

public static int binarySearch(int[] a, int fromIndex, int toIndex, int key)

参数

a - 要搜索的数组

fromIndex - 要搜索的第一个元素(包括)的索引

toIndex - 要搜索的最后一个元素(排他)的索引

key - 要搜索的值

public static void main(String[] args) {
    int[] arr1 = new int[] { 4,3,2,1 };
    System.out.println(Arrays.binarySearch(arr1, 3));//下标是1
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>