Java 数组

数组在计算机语言中是非常重要的集合类型,大部分计算机语言中数组具有如下三个基本特性:

  1. 一致性:数组只能保存相同数据类型元素,元素的数据类型可以是任何相同的数据类型。
  2. 有序性:数组中的元素是有序的,通过下标访问。
  3. 不可变性:数组一旦初始化,则长度(数组中预分配的元素个数)不可变。

一维数组

格式 1(推荐采用):元素类型[] 数组名;

格式 2:元素类型 数组名[];

数组元素的类型可以是基本类型,也可以是类或接口。

数组初始化

声明完成就要对数组进行初始化,数组初始化的过程就是为数组每一个元素分配内存空间。一旦初始化之后数组的长度就确定下来不能再变化了。

数组初始化可以分为静态初始化和动态初始化。

静态初始化

静态初始化就是将数组的元素放到大括号中,元素之间用逗号(,)分隔。

使用场景: 在已知数组的每一个元素内容情况下使用。

示例代码如下:

建议此种完整的形式

java 复制代码
// 完整格式
String[] nameArray = new String[] {"张飞", "店小二", "老王"};
// 简写形式
String[] nameArray = {"张飞", "店小二", "老王"};

注意:如果在返回的时候使用简写形式,会编译不通过, return {"张飞", "店小二", "老王"};。这种情况下只能写成 return new String[] {"张飞", "店小二", "老王"};

动态初始化

动态初始化使用 new 运算符分配指定长度,系统会自动为其分配默认值。语法为:new 元素数据类型[数组长度] ;。默认值的规则和类的成员变量的规则保持一致, 这里还没有介绍 new 关键字和如何新建类,所以详细说明下。

数组长度虽然可以动态确定,同样的重要在确定后就不可以变。

还有一个小细节,不能在给定初始值的同时给定长度,例如以下这种写法是是不允许的:

java 复制代码
String[] nameArray = new String[3] {"张三", "李四", "王五"};

长度要求是非负数。所以长度至少为 0。而长度为 0 的数组称为空数组,在实际生产中也有其特殊用途。

多维数组

一般可用于数学计算,比如二维数组的矩阵运算等场景。

多维数组一般用得不多,超过 3 层后可读性很差,很难维护了。 下面主要讲介绍二维数组。

二维数组声明

当数组中每个元素又可以带有多个下标时,这种数组就是"多维数组"。Java 中声明二维数组需要有两个中括号,具体有三种语法如下:

java 复制代码
元素数据类型[][] 数组变量名;
元素数据类型 数组变量名[][];
元素数据类型[] 数组变量名[];

二维数组的初始化

二维数组的初始化也分为静态初始化和动态初始化。

静态初始化

java 复制代码
int[][] intArray = new int[][] {
  { 1, 2, 3 }, 
  { 11, 12, 13 }, 
  { 21, 22, 23 }
};

提示 严格意义上说 Java 中并不存在真正意义上的多维数组,可认为依旧是一维数组,不过数组中的元素也是数组,以此类推三维数组就是数组的数组的数组了,例如 { { {1, 2}, {3} }, { {21}, {22, 23} } } 表示一个三维数组。

动态初始化

语法: new 元素数据类型[高维数组长度][低维数组长度];

不规则数组

由于 Java 多维数组是数组的数组,因此会衍生出一种不规则数组。

动态初始化不规则数组比较麻烦,不能使用 new int[4][3] 语句,而是需要先初始化较高维数组,然后再分别逐个初始化低维数组。代码如下:

java 复制代码
// 先初始化高维数组为 4
int xxxArray[][] = new int[4][]; 
// 逐一初始化低维数组
xxxArray[0] = new int[2];
xxxArray[1] = new int[1];
xxxArray[2] = new int[3];
xxxArray[3] = new int[3];

数组的访问

通过下标访问

数组有一个 length 属性,且只读。数组的长度,至少为 0。

通过下标进行访问。例如 arr[0] 表示第 1 个元素, arr[1] 表示第 2 个元素,依此类推直到 arr[length - 1]。

我对 length 的理解:由于 length 的类型为 int 类型,理论上可以表示的最大长度是 int 类型的最大值。但是这样做在运行行可能会抛出 OOM 异常。实际上一般也用不到长度这么长的数组。

java 复制代码
// 静态初始化
int arr[] = new int[3];
// 设置值
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
// 直接输出将打印内存地址
System.out.println(arr);
// 输出数组的长度
System.out.println(arr.length);
// 输出数组的第 0 个元素
System.out.println(arr[0]);
System.out.println(arr[1]);
// 输出数组的第 2 个元素
System.out.println(arr[2]);
// 输出数组的第 3 个元素 将产生数组越界异常
System.out.println(arr[3]);

数组遍历

普通遍历

java 复制代码
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}

使用 foreach 遍历

foreach 关键字。这是 jdk 1.5 新增的关键字。iterate over an array or Iterable。可用迭代数组和 Iterable 对象,比如一些常见的集合类型。使用 foreach 的好处是它隐藏了下标, 数组遍历强烈建议使用。除非是需要下标值。

java 复制代码
for (类型 变量: 数组) {
    // do something
}

理解数组的内存结构

数组类型和基本类型是有明显不同的,一个基本类型变量,内存中只会有一块对应的内存空间。但数组有两块:一块用于存储数组内容本身(栈内存),另一块用于存储内容的位置(堆内存)。

数组中常见的异常(Exception): 访问到不存在的角标: ArrayIndexOutOfBoundsException

加餐

命令行数组

Java 的 main 方法参数 String[] args 其实也是一个字符串数组,这里可以通过 java Demo hello world 往数组传至。

以下 eclipse 添加参数的截图。

工具类 Arrays 的使用

提供了数组拷贝由 java.lang.System 的静态方法

java 复制代码
public static native void arraycopy(Object src, int  srcPos, Object dest, int destPos, int length)

// 数组打印
Arrays.toString(array);
Arrays.deepToString

// 升序排列
Arrays.sort(array);

// 数组的赋值
Arrays.copyOf
Arrays.copyOfRange

// 数组元素的折半查找
binarySearch(Object[] a, Object key)

小案例

java 复制代码
int[] array = { 1, 5, 3 };
int[] bArray = { 11, 55, 33 };

// 数组拷贝
System.arraycopy(array, 1, bArray, 1, 1);
System.out.println(Arrays.toString(bArray));

// 数组打印
System.out.println(Arrays.toString(array));

// 升序排列
Arrays.sort(array);
System.out.println(Arrays.toString(array));

三方数组增强工具

Apache Commons Lang 库提供了对数组的增强操作类 ArrayUtils。

下面这个例子实现了数组的翻转。

java 复制代码
ArrayUtils.reverse(array);

参考

  • 丁振凡编著,《Java 语言程序设计(第2版)》华东交大版,2014.9
  • Java 编程的逻辑-微信读书 weread.qq.com/web/reader/...
相关推荐
爬山算法8 分钟前
Maven(6)如何使用Maven进行项目构建?
java·maven
.生产的驴12 分钟前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
爱学的小涛20 分钟前
【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解
java·开发语言·笔记·后端·nio
吹老师个人app编程教学21 分钟前
详解Java中的BIO、NIO、AIO
java·开发语言·nio
爱学的小涛21 分钟前
【NIO基础】NIO(非阻塞 I/O)和 IO(传统 I/O)的区别,以及 NIO 的三大组件详解
java·开发语言·笔记·后端·nio
北极无雪25 分钟前
Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析
java·开发语言·后端·学习·spring
琴智冰29 分钟前
SpringBoot
java·数据库·spring boot
binqian29 分钟前
【SpringSecurity】基本流程
java·spring
猿小蔡-Cool1 小时前
CPU 多级缓存
java·spring·缓存
gopher95111 小时前
final,finally,finalize的区别
java·开发语言·jvm