Java 的数组详解

4460 admin
世界杯历届冠军名单

数组的定义

数组是相同类型数据的有序集合

数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成

其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标(编号、标记)来访问它,下标是从 0 开始的,如果是存 10 个数组,那么下标是从 0 ~ 9 的

代码举例

public class ArrayDemo01 {

//变量的类型 变量的名字 = 变量的值

public static void main(String[] args) {

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

System.out.println(nums[0]); //1 打印下标元素为0的内容

}

}

数组的声明创建

首先必须声明数组变量,才能在程序中使用数组

语法

dataType[] arrayRefVar; //首选的方法

dataTypr arrayRefVar[]; //效果相同,但不建议

代码举例

//数组类型[] 数组名字;

int[] nums;

int nums[];

Java 语言使用 new 操作符来创建数组

语法

dataType[] arrayRefVar = new dataType[srraySise];

代码举例

//数组类型[] 数组名字 = new 数组类型[数组容量];

int[] nums = new int[10]

数组的元素是通过索引访问的,数组索引从 0 开始

获取数组长度

//数组名字.length

arrays.length //nums.length

代码总结举例

public class ArrayDemo01 {

//变量的类型 变量的名字 = 变量的值

public static void main(String[] args) {

//int[] nums = {1,2,3,4,5,6,7,8,9,10}; //一次性给数组元素赋值

//System.out.println(nums[0]); //1

//2种定义数组方法

int[] nums; //首选定义方法

int nums2[]; //第二种定义方法 C语言语法,为了让C语言程序员而兼容。

//int[] nums = new int[10]; //一步到位定义好存放数组大小

nums = new int[10]; //这里面可以存放 10 个 int 类型的数字

//依次给数组元素赋值

nums[0] = 1;

nums[1] = 2;

nums[2] = 3;

nums[3] = 4;

nums[4] = 5;

nums[5] = 6;

nums[6] = 7;

nums[7] = 8;

nums[8] = 9;

nums[9] = 10;

//计算所有元素的和

int sum = 0;

//获取数组长度:arrays.length

for (int i = 0; i < nums.length; i++) {

sum = sum + nums[i];

}

System.out.println("总和为:" + sum); //55

}

}

数组的内存

数组内存分析

画图分析数组内存

数组的三种初始化

静态初始化:创建的同时赋值

代码语法举例

int[] a = {1, 2, 3}; //正常的静态初始化

Man[] mans = {new Man(1, 1), new Man(2, 2)}; //引入的静态初始化

动态初始化:包含默认初始化,未赋值的元素默认为 0

代码语法举例

int[] a = new int[3];

a[0] = 1;

a[1] = 2;

System.out.println(a[0]); //1

System.out.println(a[1]); //2

System.out.println(a[3]); //0 未赋值则为 0 默认初始化

数组的默认初始化:数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化(0)

代码语法举例

int[] a = new int[1];

System.out.println(a[1]); //0 未赋值则为 0

数组的四个基本特点

其长度是确定的。数组一旦被创建,它的大小就是不可以改变的

其元素必须是相同类型,不允许出现混合类型

数组中的元素可以是任何数据类型,包括基本类型和引用类型

数组变量属于引用类型,数组也可以看成是对象,数组指定每个元素相当于该对象的成员变量。数组本身就是对象,Java 中对象是在堆中的,因此数组无论保护原始类型还是其他对象类型,数组对象本身是在堆中的

数组的边界

下标的合法区间:[0, length-1],如果越界就会报错 ArrayIndexOutOfBoundsException (数组下标越界异常)

代码举例

public class ArrayDemo02 {

public static void main(String[] args) {

//静态初始化:创建的同时赋值

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

for (int i = 0; i < a.length; i++) {

System.out.println(a[i]);

//正常遍历出 a 这个数组内所有值

}

/*

for (int i = 0; i <= a.length; i++) { //将 i < a.length 改为 i <= a.length

System.out.println(a[i]);

//先报错随后正常遍历出a这个数组内所有值

//下标为 数组长度 -1,例如 a[0] = 1 而不是 a[1] = 1。当 for 循环走到 i <= a.length 时,下标为 8 (a[8]),a(8)未赋值且超过数组最大长度因此会越界报错

}

*/

}

}

结论

数组是相同数据类型 (数据类型可以为任意类型) 的有序集合

数组也是对象。数组元素相当于对象的成员变量

数组长度是确定不可改变的。越界则报错 ArrayIndexOutOfBoundsException (数组下标越界异常)

数组的使用

普通的 For 循环

public class ArrayDemo03 {

public static void main(String[] args) {

int[] arrays = {1, 2, 3, 4, 5};

//打印全部的数组元素

for (int i = 0; i < arrays.length; i++) {

System.out.println(arrays[i]);

}

//计算所有元素的和

int sum = 0;

for (int i = 0; i < arrays.length; i++) {

sum += arrays[i]; //sum = sum + arrays[i]

}

System.out.println("sum=" + sum);

//查找最大元素

int max = arrays[0];

for (int i = 1; i < arrays.length; i++) { //arrays[0] 已经是 max 的默认值,因此我们改成 i = 1 ,从 1 开始

if (arrays[i] > max){

max = arrays[i];

}

}

System.out.println("max=" + max);

}

}

For-Each 循环

public class ArrayDemo04 {

public static void main(String[] args) {

int[] arrays = {1, 2, 3, 4, 5};

//JDK1.5特性 只遍历全部值,没有下标

for (int array : arrays) { //增强型 for 循环,关键字 arrays.for 自动生成

System.out.println(array);

}

}

}

数组作方法入参

public class ArrayDemo04 {

public static void main(String[] args) {

int[] arrays = {1, 2, 3, 4, 5};

//调用打印数组元素方法

printArray(arrays); //更好的遍历数组,在需要时可以取到下标

}

//打印数组元素

public static void printArray(int[] arrays){ //更好的遍历数组,在需要时可以取到下标

for (int i = 0; i < arrays.length; i++) {

System.out.print(arrays[i] + " ");

}

}

}

数组作返回值

public class ArrayDemo04 {

public static void main(String[] args) {

int[] arrays = {1, 2, 3, 4, 5};

int[] result = reverse(arrays); //调用反转数组方法

printArray(result); //更好的遍历数组,在需要时可以取到下标

}

//打印数组元素

public static void printArray(int[] arrays){ //更好的遍历数组,在需要时可以取到下标

for (int i = 0; i < arrays.length; i++) {

System.out.print(arrays[i] + " ");

}

}

//反转数组

public static int[] reverse(int[] arrays){

int[] result = new int[arrays.length]; //保证传入的数组不会超出最大长度

//反转的操作

for (int i = 0, j = result.length-1; i < arrays.length; i++, j--) { //result.length-1 是因为下标从 0 开始而 length 长度是从 1 开始,一次使用两个组合 for 循环

result[j] = arrays[i];

}

return result; //返回值

}

}

多维数组

多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一堆数组,其每一个元素都是一个一堆数组

二维数组

语法

int a[][] = new int[2][5];

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

代码举例

public class ArrayDemo05 {

public static void main(String[] args) {

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

//int array[][] = new int[2][5]; //相当于一个数组内嵌套了 2 层的数组

/*

//解析如下:

a =

{

{1, 2}, //2 层嵌套的数组

{3, 4},

{5, 6},

{7, 8},

{9, 10},

}

*/

//打印指定元素的值

System.out.println(array[0][0]); //1

System.out.println(array[0][1]); //2

System.out.println(array[1][1]); //4

System.out.println(array.length); //5 5列

System.out.println(array[0].length); //2 2行

}

}

解析:以上二维数组 a 可以看成一个两行五列的数组

三维数组

语法

int a[][][] = new int[][][];

int[][][] a = {{{1, 2}, {3, 4}}};

代码举例

public class ArrayDemo05 {

public static void main(String[] args) {

int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};

//int array[][][] = new int[2][2][3]; //相当于一个数组内嵌套了 3 层的数组

/*

//解析如下:

a =

{

{

{1, 2},

{3, 4},

},

{

{5, 6},

{7, 8},

},

{

{9, 10},

{11, 12},

},

//3 层嵌套的数组

}

*/

//打印指定元素的值

System.out.println(array[0][0][0]); //1

System.out.println(array[0][0][1]); //2

System.out.println(array[1][1][1]); //8

System.out.println(array.length); //3 3组

System.out.println(array[0].length); //2 2列

System.out.println(array[0][1].length); //2 2行

}

}

解析:以上三维数组 a 可以看成一个两行两列三组的数组

...

遍历多维数组

遍历二维数组代码举例

public class ArrayDemo05 {

public static void main(String[] args) {

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

//遍历

for (int i = 0; i < array.length; i++) {

for (int j = 0; j < array[i].length; j++) {

System.out.println(array[i][j]);

}

}

}

}

遍历三维数组代码举例

public class ArrayDemo06 {

public static void main(String[] args) {

int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};

//遍历

for (int i = 0; i < array.length; i++) {

for (int j = 0; j < array[i].length; j++) {

for (int k = 0; k < array[i][j].length; k++) {

System.out.println(array[i][j][k]);

}

}

}

}

}

...

数组的 Arrays 类

调用数组的工具类 java.util.Arrays

import java.util.Arrays; //调用工具类

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

Arrays.sort(a);//所有的 Arrays 都需要调用 import java.util.Arrays; 工具类

}

由于数组对象并没有什么方法可以供我们调用,但 API 中提供了一个工具类 Arrays 供我们使用,从而可以对数据对象进行一些基础操作

查看 Arrays 类内所有方法

方法①:打开 JDK 帮助文档(搜索 Arrays)查看

方法②:直接使用 IDEA 查看源代码

创建 main 方法后键入"Arrays"如下图,点击即可调用它的工具类

鼠标停放在调用的工具类 java.util.Arrays 的 Arrays 关键字几秒会弹出一个窗口,以下操作后点击 跳转到源 可以索引到方法源

进入 Arrays 源代码内后下方可以看到 Arrays 点击它即可自行查看 Arrays 内所有的源方法以及使用方法

Arrays 类中的方法都是 static 修饰的静态方法,在使用的时候可以直接使用类名进行调用,而“不用”使用对象来调用(注意:是“不用”而不是“不能”)

import java.util.Arrays;

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

//直接调用

printArray(a); //[1, 2, 3, 4, 3554, 65, 6, 231324]

}

//创建方法 使用 static 修饰符

public static void printArray(int[] a){

System.out.print("[");

for (int i = 0; i < a.length; i++) {

String symbol = "";

if (i != a.length-1){

symbol = ", ";

}else{

symbol = "";

}

System.out.print(a[i] + symbol);

}

System.out.println("]");

}

}

它具有以下常用功能:

打印数组元素:通过 toString 方法直接遍历

import java.util.Arrays;

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

//打印数组元素:Arrays.tostring

System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 3554, 65, 6, 231324]

//了解原理后咱们也可以自己创建方法来实现

//可以但不建议,大家了解一下就好。不建议重复造轮子!

printArray(a); //[1, 2, 3, 4, 3554, 65, 6, 231324]

}

//创建方法

public static void printArray(int[] a){

System.out.print("[");

for (int i = 0; i < a.length; i++) {

String symbol = "";

if (i != a.length-1){

symbol = ", ";

}else{

symbol = "";

}

System.out.print(a[i] + symbol);

}

System.out.println("]");

}

}

给数组重新赋值:通过 fill 方法重新填充

import java.util.Arrays;

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

//数组填充(重新赋值)

//Arrays.fill(a, 0); //全部重新赋值为 0

//System.out.println(Arrays.toString(a)); //[0, 0, 0, 0, 0, 0, 0, 0]

Arrays.fill(a, 2, 4, 0); //包括下标为 2 但不包括下标为 4 之间的元素重新赋值为 0

System.out.println(Arrays.toString(a)); //[1, 2, 0, 0, 3554, 65, 6, 231324]

}

}

对数组排序:通过 sort 方法,按升序排序

import java.util.Arrays;

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

Arrays.sort(a);//数组进行排序:升序

System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 6, 65, 3554, 231324]

}

}

比较数组:通过 equals 方法比较数组中元素值是否相等

import java.util.Arrays;

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

//给数组中的元素值比较是否相等

int[] b = {0};

if(Arrays.equals(a, b)) { //不相等

System.out.println("相等");

}else{

System.out.println("不相等");

}

int[] c = {1,2,3,4,3554,65,6,231324};

if(Arrays.equals(a, c)) { //相等

System.out.println("相等");

}else{

System.out.println("不相等");

}

}

}

查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作

import java.util.Arrays;

public class ArraysDemo07 {

public static void main(String[] args) {

int[] a = {1,2,3,4,3554,65,6,231324};

//对数组进行二分查找法操作

Arrays.sort(a); //使用二分查找法的数组必须是有序的

System.out.println(Arrays.binarySearch(a, 0)); //2 查找元素值 3,找到后返回下标。

/*

若未找到元素值则会出现以下情况:

[1] 搜索值不是数组元素值,大小在所有数组范围内,下标从1开始计数,返回“ - 按顺序插入点的下标”

[2] 搜索值是数组元素值,下标从0开始计数,返回搜索值的下标

[3] 搜索值不是数组元素值,且大于数组内所有元素值,返回 – (数组最大长度 + 1)

[4] 搜索值不是数组元素值,且小于数组内所有元素值,返回 – 1

*/

}

}

...

数组的冒泡排序

冒泡排序无疑是最为出名的排序算法之一 (总共有八大排序)

冒泡排序的步骤 (两两比较)

比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就将它们交换位置

每一次比较,都会产生出一个最大或者最小的数字

下一轮则可以少一次排序

依次循环,直到结束

代码举例

import java.util.Arrays;

public class ArrayDemo08 {

public static void main(String[] args) {

int[] a = {2,4,2,1,3,5,6,66,77,7,4,0};

int[] sort = sort(a); //调用完我们创建的排序方法后返回一个排序后的数组

System.out.println(Arrays.toString(sort));

}

//冒泡排序方法

public static int[] sort(int[] array){

//临时变量

int temp = 0;

//外层循环:判断我们这个要走多少次

for (int i = 0; i < array.length-1; i++) { //当循环走到最后的下标时无法与下个下标进行比较就会溢出,因此这里需要 array.length-1 预留一个位置进行比较排序

//内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置

for (int j = 0; j < array.length-1-i; j++) { //每次遍历比较都要排除掉i且给最后下标的元素值预留1个位置,因此需要 array.length-1-i

if (array[j+1]

temp = array[j]; //将本次对比的元素值存进临时变量

array[j] = array[j+1];

array[j+1] = temp;

}

}

}

return array; //排序完成后返回数组

}

}

冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人尽皆知

我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为 O(n2)

优化代码举例

import java.util.Arrays;

public class ArrayDemo08 {

public static void main(String[] args) {

int[] a = {2,4,2,1,3,5,6,66,77,7,4,0};

int[] sort = sort(a); //调用完我们创建的排序方法后返回一个排序后的数组

System.out.println(Arrays.toString(sort));

}

//冒泡排序方法

public static int[] sort(int[] array){

//临时变量

int temp = 0;

//外层循环:判断我们这个要走多少次

for (int i = 0; i < array.length-1; i++) { //当循环走到最后的下标时无法与下个下标进行比较就会溢出,因此这里需要 array.length-1 预留一个位置进行比较排序

boolean flag = false; //通过 flag 标识减少没有意义的比较

//内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置

for (int j = 0; j < array.length-1-i; j++) { //每次遍历比较都要排除掉i且给最后下标的元素值预留1个位置,因此需要 array.length-1-i

if (array[j+1]

temp = array[j]; //将本次对比的元素值存进临时变量

array[j] = array[j+1];

array[j+1] = temp;

flag = true;

}

}

if (flag == false){ //只要未执行以上循环则会终止所有循环继续走下面的代码。节省时间成本

break;

}

}

return array; //排序完成后返回数组

}

}

稀疏数组

稀疏数组的介绍

当一个数组中大部分元素为 0,或者为同一数值的数组时,可以使用稀疏数组来保存该数组

稀疏数组的处理方式:

记录数组一共有几行几列,有多少个不同值

把具有不同值的元素和行列以及值记录在一个小规模的数组中,从而缩小程序的规模

如下图 (左边是原始数组,右边是稀疏数组)

下标 0 的稀疏数组:记录整个数组有 6 行 7 列 8 个不为 0 的有效值

下标 1~8 的稀疏数组:记录每个有效值的位置。例如下标 1 中的 22 ,在数组中,下标从 0 开始计数,那么在稀疏数组中记录为 0 3 22,即为在下标为 0 的行,下标为 3 的列,记录值为 22

稀疏数组的应用

要求:编写五子棋游戏中,有存盘退出和续上盘的功能

问题分析:因为该二维数组的很多值是默认值 0,因此记录了很多没有意义的数据

解决方法:稀疏数组

代码举例

public class ArrayDemo09 {

public static void main(String[] args) {

//1.创建一个二维数组 11*11(11行11列) 0:没有棋子 1:黑棋 2:白棋

int[][] array1 = new int[11][11];

array1[1][2] = 1; //黑棋位于2行3列(数组从 0 计数)

array1[2][3] = 2; //白棋位于3行4列(数字从 0 计数)

//输出原始的数组

System.out.println("输出原始的数组");

for (int[] ints : array1) {

for (int anInt : ints) {

System.out.print(anInt + "\t");

}

System.out.println();

}

//转换为稀疏数组来保存

//1. 获取有效值的个数

int sum = 0;

for (int i = 0; i < array1.length; i++) { //array1.length 取二维数组嵌套的数组个数 11行

for (int j = 0; j < array1[i].length; j++) { //array1[0].length 取遍历下标 i 的子数组中值的个数 11列

if (array1[i][j] != 0){

sum++;

}

}

}

System.out.println("有效值的个数:" + sum);

//2. 创建一个稀疏数组

int[][] array2 = new int[sum+1][3]; //之所以行数为有效值个数加 1 是因为需要多加 1 行记录行总数、列总数、有效值个数。固定 3 列

//多出来的 1 行用用以下代码赋值记录行总数、列总数、有效值个数

array2[0][0] = 11;

array2[0][1] = 11;

array2[0][2] = sum;

//遍历二维数组,将非零的值(有效值),存放在稀疏数组中

int count = 0;

for (int i = 0; i < array1.length; i++) {

for (int j = 0; j < array1[i].length; j++) {

if (array1[i][j] != 0){

count++; //行递增

//利用行递增给稀疏数组赋值记录

array2[count][0] = i;

array2[count][1] = j;

array2[count][2] = array1[i][j];

}

}

}

//3. 输出稀疏数组

System.out.println("稀疏数组");

for (int i = 0; i < array2.length; i++) {

System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2]);

}

//数组还原归位

//1. 读取稀疏数组

int[][] array3 = new int[array2[0][0]][array2[0][1]]; //根据数组默认初始化,至此一行代码已还原所有 0 值归为

//2. 给其中的元素还原它的值

for (int i = 1; i < array2.length; i++) { //还原过程中,头部记录的综合信息不需要读取,因此 i=1,从下标 1 开始

array3[array2[i][0]][array2[i][1]] = array2[i][2]; //在已记录的有效值位置还原有效值

}

//3. 打印

System.out.println("打印还原的数组");

for (int[] ints : array3) {

for (int anInt : ints) {

System.out.print(anInt + "\t");

}

System.out.println();

}

}

}

斗罗大陆:魂灵还分类别?唐舞麟拥有不屈魂灵,霍雨浩魂灵最多 5G黑科技赋能加码,咪咕咖啡开启世界杯观赛新视角