数组的概述
Array——多个相同类型的数据按顺序(有序性)排列的集合。 使用一个名字命名,通过编号的方式对这些数据进行统一管理。 数组名、索引、元素、数组的长度> > 数组的分类: 按照维度:一维数组、二维数组、三维数组 按照元素的数据类型:基本数据类型元素数组、引用数据类型元素数组(对象数组)
- 数组本身是引用数据类型,而数组中的元素可以是任何数据类型;
- 创建数组对象会在内存中开辟一块连续的空间,而数组名中引用的是这块连续空间的首地址;
- 数组的长度一旦确定,就不能修改;
- 可直接通过下标或索引的方式快速调用指定位置的元素。
一维数组的使用
一维数组的声明和初始化
- 声明:
type var[]
;(或type[] var;
)
不能在数组的声明过程中指定其长度。 - 初始化:
- 静态初始化:数组的初始化伴随着数组元素的赋值;
- 动态初始化:数组的初始化和数组元素的赋值异步进行。
初始化结束,数组的长度也就确定了。
- 声明:
class OneDimensionalArray1 {
public static void main(String[] args) {
int[] IDs; // 声明一个名为 IDs 的基本数据类型(int)的数组
IDs = new int[]{1001, 1002, 1003, 1004}; // 将大括号中 int 型的元素用静态的方式初始化到数组 IDs 中
String[] names = new String[5]; // 声明一个名为 names 的引用数据类型(String)数组后,动态地将其初始化其长度为 5
}
}
访问数组指定位置的元素
names[0] = "张三"; // 索引从 0 开始
names[1] = "李四";
names[2] = "王五";
names[3] = "辣鸡";
names[4] = "航航";
获取一维数组长度
使用属性
<array>.length
获取数组的长度。
遍历一维数组
for (int i = 0; i < names.length; i++) {
System.out.print(names[i]);
}
增强for循环:
for (String name : names) {
System.out.print(name);
}
一维数组元素的默认初始化值
class OneDimensionalArray2 {
public static void main(String[] args) {
byte[] bytes = new byte[3];
short[] shots = new short[3];
int[] ints = new int[3];
long[] longs = new long[3];
float[] floats = new float[3];
boolean[] booleans = new boolean[3];
char[] chars = new char[3];
String[] strings = new String[3];
for (byte i : bytes) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (short i : shots) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (int i : ints) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (long i : longs) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (float i : floats) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (boolean i : booleans) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (char i : chars) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
for (String i : strings) {
System.out.print("\t" + "i = " + i);
}
System.out.println();
}
}
运行结果:
i = 0 i = 0 i = 0
i = 0 i = 0 i = 0
i = 0 i = 0 i = 0
i = 0 i = 0 i = 0
i = 0.0 i = 0.0 i = 0.0
i = false i = false i = false
i = i = i =
i = null i = null i = null
一维数组内存解析
- 方法区中包含“常量池”、“静态域”以及类加载的相关信息;
- 栈中主要存放“局部变量”;
- 堆中存放
new
出来的结构:对象、数组。
分析示例
分析下列代码在内存中分配并解析的过程:
public static void main(String[] args) {
int[] arr1 = new int[]{1, 2, 3};
String[] arr2 = new String[4];
arr2[1] = "刘德华";
arr2[2] = "张学友";
arr2 = new String[3];
}
对于方法 中的变量,都是局部变量 。 案例中,
main
方法中的变量arr1
、arr2
都是局部变量。 在堆中,用连续空间第一个元素的16进制地址值表示这个对象的地址。将这个地址与new
出来的对象名关联后,可通过对象名指向这个连续空间。垃圾回收:通过引用计数算法对未被指针所用的对象执行删除。
方法执行完毕后,局部变量将不处在作用域中——出栈、垃圾回收。
练习1
升景坊单间短期出租 4 个月,550 元/月,空调、卫生间、厨房齐全。求租客一枚,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。电话号码如下:
class contactInformationOfRental {
public static void main(String[] args) {
int[] arr = new int[]{8, 2, 1, 0, 3};
int[] index = new int[]{2, 0, 3, 2, 4, 0, 1, 3, 2, 3, 3};
StringBuilder tel = new StringBuilder();
for (int j : index) {
tel.append(arr[j]);
}
System.out.println("联系方式:" + tel);
}
}
运行结果:
联系方式:18013820100
练习2
class GetGradesForGrades {
public static void main(String[] args) {
System.out.print("请输入待录入的学生成绩数:");
Scanner scanner = new Scanner(System.in);
int amountOfStudents = scanner.nextInt(), topScore = -2147483648;
int[] scores = new int[amountOfStudents];
for (int i = 0; i < scores.length; i++) {
System.out.print("学生" + (i + 1) + ":");
int score = scanner.nextInt();
scores[i] = score;
if (score > topScore) {
topScore = score;
}
}
System.out.println("\n这" + amountOfStudents + "个学生中,成绩的最高分是:" + topScore + "\n");
System.out.println("次序\t成绩\t等级");
int order = 0;
for (int score : scores) {
System.out.println((order++ + 1) + "\t" + score + "\t" +
((topScore - score <= 10) ? "A"
: (topScore - score <= 20) ? "B"
: (topScore - score <= 30) ? "C" : "D")
);
}
}
}
运行结果:
请输入待录入的学生成绩数:5
学生1:56
学生2:74
学生3:89
学生4:41
学生5:89
这5个学生中,成绩的最高分是:89
次序 成绩 等级
1 56 D
2 74 B
3 89 A
4 41 D
5 89 A
多维数组的使用
以二维数组为常用。Java 中多维数组不必都是规则矩阵形式。 我们可以把二维数组理解成一维数组作为另一一维数组的元素的形式。
声明和初始化
class DoubleDimensionalArray1 {
public static void main(String[] args) {
int[][] arr1 = {{1, 2, 3}, {4, 5}, {6, 7, 8}}; // 二维数组的声明和静态初始化(类型推断)
String[][] arr2 = new String[3][2]; // 二维数组的声明和动态初始化之一
String[][] arr3 = new String[3][]; // 二维数组的声明和动态初始化之二
System.out.println("arr1 = " + Arrays.deepToString(arr1));
System.out.println("arr2 = " + Arrays.deepToString(arr2));
System.out.println("arr3 = " + Arrays.deepToString(arr3));
}
}
运行结果:
arr1 = [[1, 2, 3], [4, 5], [6, 7, 8]]
arr2 = [[null, null], [null, null], [null, null]]
arr3 = [null, null, null]
数组的声明和静态初始化在同一逻辑行时,可省略
new <type>
——类型推断。注意特殊写法情况:
int[] x, y[];
x
是一维数组,y
是二维数组 可以通过这种方式初始化:int[] x = new int[0], y[] = new int[0][];
- 一维数组:
int[] x
、int x[]
;- 二维数组:
int[][] y
、int[] y[]
、int y[][]
。
- 二维数组初始化方式一:
<type>[][] arrayName = new <type>[<index1>][<index2>]
(适用于矩阵数据)- 二维数组初始化方式二:
<type>[][] arrayName = new <type>[<index1>][]
(适用于不确定元素个数的情景)
根据索引访问元素
获取数组长度
遍历二维数组
class DoubleDimensionalArray2 {
public static void main(String[] args) {
char[][] arr2 = {{'a', 'b', 'c'}, {'d', 'e', 'f', 'g', 'h'}, {'k', 'l', 'm', 'n'}};
for (char[] i : arr2) {
for (char j : i) {
System.out.print("j = " + j + "; ");
}
System.out.println();
}
}
}
运行结果:
j = a; j = b; j = c;
j = d; j = e; j = f; j = g; j = h;
j = k; j = l; j = m; j = n;
二维数组元素的默认初始化值
class DoubleDimensionalArray3 {
public static void main(String[] args) {
int[] arry1 = new int[3]; // 一维数组的命名和动态初始化
System.out.println(arry1); // 一维数组的首地址值([I@e580929)
float[][] array2 = new float[4][3]; // 二维数组的命名和动态初始化
System.out.println(array2); // 指向堆中二维数组的地址([[F@1cd072a9)
System.out.println(array2[0]); // 指向内一层(这里是内层)数组的首地址([F@7c75222b)
System.out.println(array2[0][0]); // 内层元素的值(0.0)
double[][] array3 = new double[4][];
System.out.println(array3[1]); // 只初始化了外层数组,内层数组暂未初始化,但内层数组是引用数据类型(null)
// System.out.println(array3[1][0]); // 报错:NullPointerException(空指针异常)
}
}
运行结果:
[I@e580929
[[F@1cd072a9
[F@7c75222b
0.0
null
对于返回的内存地址,含义如下:
[
表示变量指向一维数组,[[
表示变量指向二维数组;I
、F
等字母表示数组中的元素数据类型;@
后连接16进制的地址值,由 JVM 通过哈希算法生成,屏蔽了计算机底层的真实地址。
- 对于多维数组的初始化方式一,如
<type>[][] arrayName = new <type>[<index1>][<index2>]
:- 外层元素:向内一层数组的首地址(是二维数组时,指向内层的首地址);
- 内层元素:与一维数组的初始化情况一致。
- 对于多维数组的初始化方式二,如
<type>[][] arrayName = new <type>[<index1>][]
:
- 外层元素:
null
(数组本身作为引用数据类型,默认初始化值是null
,并不存在地址指向未初始化的内层对象);- 内层元素:未被初始化,不可及。此时访问则报错:
NullPointerException
(空指针异常)。
二维数组的内存解析
数据结构:
- 数据间的结构关系:集合 -> 一对一 -> 一对多 -> 多对多
- 数据的存储结构:
线性表(顺序表):链表、栈(先进后出)、队列(先进先出)
树形结构:二叉树
图形结构算法: 排序算法、搜索算法
数组基础练习
使用for循环嵌套,获取多维数组中所有元素的和
class GetSumOfArray {
public static void main(String[] args) {
int[][] array = new int[][]{{3, 5, 8}, {12, 9}, {7, 0, 6, 4}};
int sum = 0;
for (int[] a : array) {
for (int i : a) {
sum += i;
}
}
System.out.println("sum = " + sum);
}
}
运行结果:
sum = 54
杨辉三角
class YangHuiTriangle {
public static void main(String[] args) {
int range = 10; // 杨辉三角的目标行数
int[][] triangleTable = new int[range][]; // 创建杨辉三角,只声明“行”
for (int line = 0; line <= range - 1; line++) { // 用行索引 line 遍历每一行
triangleTable[line] = new int[line + 1]; // 在每一行新建长为行索引的内层数组
triangleTable[line][0] = triangleTable[line][triangleTable[line].length - 1] = 1; // 每行第一个和每行最后一个
for (int i = 1; i < triangleTable[line].length - 1; i++) { // 从索引为 2 的行开始,对每行的 1~-2 个为止
triangleTable[line][i] = triangleTable[line - 1][i] + triangleTable[line - 1][i - 1];
}
}
for (int[] i : triangleTable) {
for (int j : i) {
System.out.print("\t" + j);
}
System.out.println();
}
}
}
运行结果:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
数组中的常见算法
数组元素的赋值(杨辉三角、回形数等)
杨辉三角
随机赋值并保证唯一性
创建一个长度为 6 的 int 型数组,要求数组元素的值在 1~30 之间。随机赋值并保证各元素的值各不相同。
方法一
class RandomUniqueArray1 {
public static void main(String[] args) {
int[] randomUniqueArray = new int[6]; // 新建一个长度为 6 的数值型数组
for (int i = 0; i < randomUniqueArray.length; ) { // 遍历数组的每一个索引位置
for (; ; ) { // 循环产生随机数,满足唯一性则退出循环
int getRandom = (int) (Math.random() * 30 + 1); // 获取一个区间 [1, 30] 的随机整数
boolean isTheSame = false; // isTheSame 为 false 是赋值的条件
for (int j = 0; j < i; j++) {
if (getRandom == randomUniqueArray[j]) {
isTheSame = true;
break; // 找到相同值,跳出
}
}
if (!isTheSame) { // 具有唯一性则:赋值、准备下一个、跳过用于产生随机数的循环
randomUniqueArray[i] = getRandom; // 赋值
i++; // 准备下一个
break; // 跳过产生随机数的循环
}
}
}
for (int randomUniqueInt : randomUniqueArray) {
System.out.print("\t" + randomUniqueInt);
}
}
}
方法二
class RandomUniqueArray2 {
public static void main(String[] args) {
int[] arr = new int[6];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 30) + 1; // [0,1) -> [0,30) -> [1,31)
for (int j = 0; j < i; j++) {
if (arr[i] == arr[j]) {
i--;
break;
}
}
}
for (int j : arr) {
System.out.println(j);
}
}
}