数组

数组

数组的概述

数组的理解

数组(Array),是多个相同类型数据一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理

数组的特点

数组是有序排列的

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

创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址

数组的长度一旦确定,就不能修改。

数组的分类

① 照维数:一维数组、二维数组。。。

② 照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组

一维数组的使用

一维数组的声明与初始化

正确的方式:

1
2
3
4
5
6
7
8
9
10
11
int num;//声明
num = 10;//初始化
int id = 1001;//声明 + 初始化

int[] ids;//声明
//1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
ids = new int[]{1001,1002,1003,1004};
//1.2动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[] names = new String[5];

int[] arr4 = {1,2,3,4,5};//类型推断

错误的方式:

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

一维数组元素的引用

1
2
3
4
5
6
7
通过角标的方式调用
//数组的角标(或索引从0开始的,到数组的长度-1结束。
names[0] = "王铭";
names[1] = "王赫";
names[2] = "张学良";
names[3] = "孙居龙";
names[4] = "王宏志";

数组的属性

length

1
2
System.out.println(names.length);//5
System.out.println(ids.length);

说明:

数组一旦初始化,其长度就是确定的。arr.length

数组长度一旦确定,就不可修改。

一维数组的遍历

1
2
3
for(int i = 0;i < names.length;i++){
System.out.println(names[i]);
}

数组遍历

数组遍历的常见方式有三种:传统的 for 循环、for each 遍历、还有 JDK 8 中新增的 Lambda 表达式。具体的实现请参考以下实例。

方式一:传统 for 循环

1
2
3
4
5
Integer[] arr = {2, 3, 6, 7, 9};
// 方式一:传统 for
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}

方式二:for each

1
2
3
4
5
Integer[] arr = {2, 3, 6, 7, 9};
// 方式二:for each
for (int i : arr) {
System.out.println(i);
}

方式三:JDK 8 中的 Lambda 表达式

1
2
3
Integer[] arr = {2, 3, 6, 7, 9};
// 方式三:jdk 8 Lambda
Arrays.asList(arr).forEach(x -> System.out.println(x));

其中 for each 的方式,写法更简洁,也更不容易出错,不必为数组的越界而担心(大于元素的最大下标值)。

注意:数组的访问是从 0 开始,而不是 1 开始,也就是第一个元素的获取是 arr[0],而非 arr[1]。

一维数组元素的默认初始化值

1
2
3
4
5
> 数组元素是整型:0
> 数组元素是浮点型:0.0
> 数组元素是char型:0或'\u0000',而非'0'
> 数组元素是boolean型:false
> 数组元素是引用数据类型:null

一维数组的内存解析

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
* 2. 从键盘读入学生成绩,找出最高分,并输出学生成绩等级。
成绩>=最高分-10 等级为’A’
成绩>=最高分-20 等级为’B’
成绩>=最高分-30 等级为’C’
其余 等级为’D’

提示:先读入学生人数,根据人数创建int数组,存放学生成绩。

*
*/
public class ArrayDemo1 {
public static void main(String[] args) {
//1.使用Scanner,读取学生个数
Scanner scanner = new Scanner(System.in);
System.out.println("请输入学生人数:");
int number = scanner.nextInt();

//2.创建数组,存储学生成绩:动态初始化
int[] scores = new int[number];
//3.给数组中的元素赋值
System.out.println("请输入" + number + "个学生成绩:");
int maxScore = 0;
for(int i = 0;i < scores.length;i++){
scores[i] = scanner.nextInt();
//4.获取数组中的元素的最大值:最高分
if(maxScore < scores[i]){
maxScore = scores[i];
}
}
// for(int i = 0;i < scores.length;i++){
// if(maxScore < scores[i]){
// maxScore = scores[i];
// }
// }
// System.out.println(maxScore);

//5.根据每个学生成绩与最高分的差值,得到每个学生的等级,并输出等级和成绩
char level;
for(int i = 0;i < scores.length;i++){
if(maxScore - scores[i] <= 10){
level = 'A';
}else if(maxScore - scores[i] <= 20){
level = 'B';
}else if(maxScore - scores[i] <= 30){
level = 'C';
}else{
level = 'D';
}

System.out.println("student " + i +
" score is " + scores[i] + ",grade is " + level);
}

}
}

类型于类型之间变量的赋值的规则,要么是同类型,要么满足自动类型提升

二维数组

如何理解二维数组

数组属于引用数据类型

数组的元素也可以是引用数据类型

一个一维数组A的元素如果还是一个一维数组类型的,则此数组A称为二维数组。

### 二维数组的声明与初始化

正确的方式:

1
2
3
4
5
6
7
8
9
10
int[] arr = new int[]{1,2,3};//一维数组
//静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
//动态初始化1
String[][] arr2 = new String[3][2];
//动态初始化2
String[][] arr3 = new String[3][];
//也是正确的写法:
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};//类型推断

错误的方式:

1
2
3
String[][] arr4 = new String[][4];
String[4][3] arr5 = new String[][];
int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};

如何调用二维数组元素

1
2
3
4
5
6
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//null

arr3[1] = new String[4];
System.out.println(arr3[1][0]);
System.out.println(arr3[0]);//

二维数组的属性

1
2
3
System.out.println(arr4.length);//3
System.out.println(arr4[0].length);//3
System.out.println(arr4[1].length);//4

遍历二维数组元素

1
2
3
4
5
6
for(int i = 0;i < arr4.length;i++){
for(int j = 0;j < arr4[i].length;j++){
System.out.print(arr4[i][j] + " ");
}
System.out.println();
}

二维数组元素的默认初始化值

1
2
3
4
5
6
7
8
9
10
11
12
13
规定:二维数组分为外层数组的元素,内层数组的元素
int[][] arr = new int[4][3];
外层元素:arr[0],arr[1]等
内层元素:arr[0][0],arr[1][2]等

⑤ 数组元素的默认初始化值
针对于初始化方式一:比如:int[][] arr = new int[4][3];
外层元素的初始化值为:地址值
内层元素的初始化值为:与一维数组初始化情况相同

针对于初始化方式二:比如:int[][] arr = new int[4][];
外层元素的初始化值为:null
内层元素的初始化值为:不能调用,否则报错。

### 二维数组的内存结构

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
* 使用二维数组打印一个 10 行杨辉三角。
【提示】
1. 第一行有 1 个元素, 第 n 行有 n 个元素
2. 每一行的第一个元素和最后一个元素都是 1
3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。即:
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
*
*/
public class YangHuiTest {
public static void main(String[] args) {
//1.声明并初始化二维数组
int[][] yangHui = new int[10][];
//2.给数组的元素赋值
for(int i = 0;i < yangHui.length;i++){
yangHui[i] = new int[i + 1];
//2.1 给首末元素赋值
yangHui[i][0] = yangHui[i][i] = 1;
//2.2 给每行的非首末元素赋值
//if(i > 1){
for(int j = 1;j < yangHui[i].length - 1;j++){
yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
}
//}
}
//3.遍历二维数组
for(int i = 0;i < yangHui.length;i++){
for(int j = 0;j < yangHui[i].length;j++){
System.out.print(yangHui[i][j] + " ");
}
System.out.println();
}
}
}

使用二维数组打印一个 10 行杨辉三角。

【提示】

  1. 第一行有 1 个元素, 第 n 行有 n 个元素

  2. 每一行的第一个元素和最后一个元素都是 1

  3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。即:

    yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class YangHuiTest {
public static void main(String[] args) {
//1.声明并初始化二维数组
int[][] yangHui = new int[10][];
//2.给数组的元素赋值
for(int i = 0;i < yangHui.length;i++){
yangHui[i] = new int[i + 1];
//2.1 给首末元素赋值
yangHui[i][0] = yangHui[i][i] = 1;
//2.2 给每行的非首末元素赋值
//if(i > 1){
for(int j = 1;j < yangHui[i].length - 1;j++){
yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
}
//}
}
//3.遍历二维数组
for(int i = 0;i < yangHui.length;i++){
for(int j = 0;j < yangHui[i].length;j++){
System.out.print(yangHui[i][j] + " ");
}
System.out.println();
}
}
}

img

数组的常见算法

1.数组的创建与元素赋值:

杨辉三角(二维数组)、回形数(二维数组)、6个数,1-30之间随机生成且不重复。

2.针对于数值型的数组:

最大值、最小值、总和、平均数等

3.数组的赋值与复制

int[] array1,array2;

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

3.1 赋值:

array2 = array1;

如何理解:将array1保存的数组的地址值赋给了array2,使得array1和array2共同指向堆空间中的同一个数组实体。

img

3.2 复制:

array2 = new int[array1.length];

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

array2[i] = array1[i];

}

img

如何理解:我们通过new的方式,给array2在堆空间中新开辟了数组的空间。将array1数组中的元素值一个一个的赋值到array2数组中。

4.数组元素的反转

​ //方法一:

// for(int i = 0;i < arr.length / 2;i++){

// String temp = arr[i];

// arr[i] = arr[arr.length - i -1];

// arr[arr.length - i -1] = temp;

// }

​ //方法二:

// for(int i = 0,j = arr.length - 1;i < j;i++,j–){

// String temp = arr[i];

// arr[i] = arr[j];

// arr[j] = temp;

// }

5.数组中指定元素的查找:搜索、检索

5.1 线性查找:

实现思路:通过遍历的方式,一个一个的数据进行比较、查找。

适用性:具有普遍适用性。

5.2 二分法查找:

实现思路:每次比较中间值,折半的方式检索。

适用性:(前提:数组必须有序)

6.数组的排序算法

img

\理解:**

\1)衡量排序算法的优劣:**

时间复杂度、空间复杂度、稳定性

\2)排序的分类:内部排序 与 外部排序(需要借助于磁盘)**

\3)不同排序算法的时间复杂度**

img

\4)手写冒泡排序**

\int**[] arr = \new** \int**[]{43,32,76,-98,0,64,33,-21,32,99};

​ //冒泡排序

\for**(\int** i = 0;i < arr.length - 1;i++){

\for**(\int** j = 0;j < arr.length - 1 - i;j++){

\if**(arr[j] > arr[j + 1]){

\int** temp = arr[j];

​ arr[j] = arr[j + 1];

​ arr[j + 1] = temp;

​ }

​ }

​ }

## Arrays工具类的使用

理解

① 定义在java.util包下

② Arrays:提供了很多操作数组的方法

使用

1.boolean equals(int[] a,int[] b)

判断两个数组是否相等

1
2
3
4
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = new int[]{1,3,2,4};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals);

2.String toString(int[] a)

输出数组信息

1
System.out.println(Arrays.toString(arr1));

3.void fill(int[] a,int val)

将指定值填充到数组之中。所有位置都会被填充同一个数

1
2
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));

4.void sort(int[] a)

对数组进行排序

1
2
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));

5.数组逆序

使用 org.apache.commons.lang3.ArrayUtils.reverse(arr) 方法,具体实现请参考下面代码:

1
2
3
4
5
6
7
int[] arr = {2, 8, 13, 11, 6, 7};
int[] arr = {2, 8, 13, 11, 6, 7};
// 数组正序(排序)
Arrays.sort(arr);
// 数组逆序
org.apache.commons.lang3.ArrayUtils.reverse(arr);
System.out.println(Arrays.toString(arr));

程序执行结果:[13, 11, 8, 7, 6, 2]

注意:org.apache.commons.lang3.ArrayUtils.reverse() 是数组逆序,并不是数组倒序,也就是说 ArrayUtils.reverse() 只会把数组原顺序颠倒输出,并不会自然排序后再倒序输出。

6.元素查找

int binarySearch(int[] a,int key)

1
2
3
4
5
6
7
int[] arr3 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
int index = Arrays.binarySearch(arr3, 210);
if(index >= 0){
System.out.println(index);
}else{
System.out.println("未找到");
}

7.数组拷贝

数组拷贝使用的是 Arrays.copyof() 方法,具体实现请参考下面代码:

1
2
3
int[] arr = {3, 4, 9};
int[] arr2 = Arrays.copyOf(arr, arr.length);
System.out.println(Arrays.toString(arr2));

程序执行结果:[3, 4, 9]

注意:Arrays.copyOf(array,newLength) 第二个参数 newLength 表示声明此数组的长度,可以比拷贝的数组的长度长,多出来的元素会初始化为 0 值。

8.数组填充与合并

数组填充

即为每个元素统一赋值,使用 Arrays.fill() 进行数组填充,具体实现请参考下面代码:

1
2
3
int[] arr = new int[10];
Arrays.fill(arr, 6);
System.out.println(Arrays.toString(arr));

程序执行结果:[6, 6, 6, 6, 6, 6, 6, 6, 6, 6]

注意:使用 Arrays.fill() 会覆盖原有的值,即使数组之前有赋值操作,也会被覆盖。

数组合并

使用 org.apache.commons.lang3.ArrayUtils.addAll() 方法,具体实现请参考下面代码:

1
2
3
4
5
int[] arr = {2, 8, 13, 11, 6, 7};
int[] arr2 = {66, 88};
// 合并数组
int[] arr3 = org.apache.commons.lang3.ArrayUtils.addAll(arr, arr2);
System.out.println(Arrays.toString(arr3));

程序执行结果:[2, 8, 13, 11, 6, 7, 66, 88]

数组的常见异常

1.数组角标越界异常

ArrayIndexOutOfBoundsException

1
2
3
4
5
6
int[] arr = new int[]{1,2,3,4,5};
for(int i = 0;i <= arr.length;i++){
System.out.println(arr[i]);
}
System.out.println(arr[-2]);
System.out.println("hello");

2.空指针异常

NullPointerException

1
2
3
4
5
6
7
8
9
10
11
12
13
情况一:
int[] arr1 = new int[]{1,2,3};
arr1 = null;
System.out.println(arr1[0]);

//情况二:
int[][] arr2 = new int[4][];
System.out.println(arr2[0][0]);

//情况:
String[] arr3 = new String[]{"AA","BB","CC"};
arr3[0] = null;
System.out.println(arr3[0].toString());

小知识:一旦程序出现异常,未处理时,就终止执行

数组类型转换

字符串转数组

使用 split 分隔字符串就形成了数组,请参考以下代码:

1
2
3
String str = "laowang,stone,wanglei";
String[] arr = str.split(","); // 字符串转数组
System.out.println(arr[0]);
数组转字符串

使用 Arrays.toString() 方法,请参考以下代码:

1
2
3
String[] arr = {"laowang", "stone", "wanglei"};
String str = Arrays.toString(arr);
System.out.println(str);

若要查看更多数组转字符串的方式,请查看本文面试部分的介绍。

数组转集合

使用 Arrays.asList() 方法,请参考以下代码:

1
2
3
String[] strArr = {"cat", "dog"};
List list = Arrays.asList(strArr);
System.out.println(list);
集合转数组

使用 List.toArrray() 方法,请参考以下代码:

1
2
3
4
5
6
List<String> list = new ArrayList<String>();
list.add("cat");
list.add("dog");
// 集合转换为数组
String[] arr = list.toArray(new String[list.size()]);
System.out.println(Arrays.toString(arr));

查找

查找定义

根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)

查找算法分类

1)静态查找和动态查找

注:静态或者动态都是针对查找表而言的

静态的就是先给一堆值,然后在一堆值中查找元素

动态指查找的过程中,有删除和插入操作

2)无序查找和有序查找。

无序查找:被查找数列有序无序均可

有序查找:被查找数列必须为有序数列

平均查找长度(Average Search Length,ASL)

img

其中n为查找表中元素个数,Pi为查找第i个元素的概率,通常假设每个元素查找概率相同,Pi=1/n,Ci是找到第i个元素的比较次数。

当然,有查找成功,就有查找不成功,即要查找元素不在查找表中。针对不同查找方式的查找成功与不成功,我接下来会说,这也是一我一开始有点乱的地方。

一个算法的ASL越大,说明时间性能差,反之,时间性能好,这也是显而易见的

顺序查找

顺序查找的基本思想

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

顺序查找适合于存储结构为顺序存储或链接存储的线性表。

顺序查找的代码

直接遍历一遍数组即可

二分查找

二分查找的基本思想

基本思想:也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。

元素必须是有序的,如果是无序的则要先进行排序操作。

注:折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。

二分查找的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 非递归的二分查找算法
public class BinarySearch {

// 我们的算法类不允许产生任何实例
private BinarySearch() {}

// 二分查找法,在有序数组arr中,查找target
// 如果找到target,返回相应的索引index
// 如果没有找到target,返回-1
public static int find(Comparable[] arr, Comparable target) {

// 在arr[l...r]之中查找target
int l = 0, r = arr.length-1;
while( l <= r ){

//int mid = (l + r)/2;
// 防止极端情况下的整形溢出,使用下面的逻辑求出mid
int mid = l + (r-l)/2;

if( arr[mid].compareTo(target) == 0 ) {
return mid;
}
if( arr[mid].compareTo(target) > 0 ) {
r = mid - 1;
}else {
l = mid + 1;
}
}

return -1;
}

// 测试非递归的二分查找算法
public static void main(String[] args) {

int N = 1000000;
Integer[] arr = new Integer[N];
for(int i = 0 ; i < N ; i ++)
arr[i] = new Integer(i);

// 对于我们的待查找数组[0...N)
// 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身
// 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1
for(int i = 0 ; i < 2*N ; i ++) {
int v = BinarySearch.find(arr, new Integer(i));
if (i < N) {
assert v == i;
}else {
assert v == -1;
}
}

return;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 递归的二分查找算法
public class BinarySearch2 {

// 我们的算法类不允许产生任何实例
private BinarySearch2() {}

private static int find(Comparable[] arr, int l, int r, Comparable target){

if( l > r )
return -1;

//int mid = (l+r)/2;
// 防止极端情况下的整形溢出,使用下面的逻辑求出mid
int mid = l + (r-l)/2;

if( arr[mid].compareTo(target) == 0 ) {
return mid;
}else if( arr[mid].compareTo(target) > 0 ) {
return find(arr, l, mid - 1, target);
}else {
return find(arr, mid + 1, r, target);
}
}

// 二分查找法,在有序数组arr中,查找target
// 如果找到target,返回相应的索引index
// 如果没有找到target,返回-1
public static int find(Comparable[] arr, Comparable target) {

return find(arr, 0, arr.length-1, target);
}

// 测试递归的二分查找算法
public static void main(String[] args) {

int N = 1000000;
Integer[] arr = new Integer[N];
for(int i = 0 ; i < N ; i ++) {
arr[i] = new Integer(i);
}
// 对于我们的待查找数组[0...N)
// 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身
// 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1
for(int i = 0 ; i < 2*N ; i ++) {
int v = BinarySearch2.find(arr, new Integer(i));
if (i < N) {
assert v == i;
}else {
assert v == -1;
}
}

return;
}
}

## 相关面试题

1. 数组和集合有什么区别?

答:数组和集合的区别如下:

  • 集合可以存储任意类型的对象数据,数组只能存储同一种数据类型的数据;
  • 集合的长度是会发生变化的,数组的长度是固定的;
  • 集合相比数组功能更强大,数组相比集合效率更高。

2. 以下代码访问数组元素打印的结果是多少?

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

答:程序编译报错,在 Java 中初始化数组时,如果直接给数组赋值,不能声明数组长度;如果声明了数组长度,则不能赋值给数组,否则编译器报错。

正确的写法如下:

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

输出的结果为:5,访问元素从 0 开始。

3. 执行以下代码会输出什么结果?

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
int[] arr = {2, 3, 4, 8};
change(arr);
System.out.println(arr[2]);
}
private static void change(int[] arr) {
for (int i = 0; i < arr.length; i++) {
if (i % 2 == 0) {
arr[i] *= i;
}
}
}

答:输出的结果是 8。

题目解析:在 Java 中数组本质是引用类型,因此在调用方法中修改数组,就是对原数组本身的修改。

4. 以下程序打印的结果是多少?

1
2
3
4
int[] intArr = new int[3];
String[] StrArr = new String[3];
System.out.println(intArr[1]);
System.out.println(StrArr[1]);

答:以上程序打印的结果是:0 和 null。

题目解析:new int[3] 相当于声明了数组的长度为 3,每个元素初始化为 0,而 new String[3] 相当于声明了数组的长度为 3,每个元素初始化为 null。

5. 数组转换字符串有哪些方式?

答:数组转换字符串,有以下几种方式。

方式一:遍历拼接,完整代码如下:

1
2
3
4
5
6
7
8
String[] arr = {"laowang", "stone", "wanglei"};
StringBuffer sb = new StringBuffer();
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);
if (i != arr.length - 1)
sb.append(",");
}
System.out.println(sb.toString());

方式二:Arrays.toString() 转换,完整代码如下:

1
2
3
String[] arr = {"laowang", "stone", "wanglei"};
String str2 = Arrays.toString(arr);
System.out.println(str2);

方式三:StringUtils.join() 转换,完整代码如下:

1
2
3
String[] arr = {"laowang", "stone", "wanglei"};
String str3 = StringUtils.join(Arrays.asList(arr), ","); // 使用英文逗号分隔
System.out.println(str3);

6. 数组遍历有哪几种方式?

答:常见的数组遍历有以下三种方式。

  • 传统 for 循环,如 for (int i = 0; i < arr.length; i++) { //…… }
  • for each 循环,如 for (int i : arr) { //…… }
  • jdk 8 Lambda 方式,如 Integer[] arr = {2, 3, 6, 7, 9}; Arrays._asList_(arr).forEach(x -> System._out_.println(x));

7. 以下数组比较的结果分别是什么?

1
2
3
4
5
String[] strArr = {"dog", "cat", "pig", "bird"};
String[] strArr2 = {"dog", "cat", "pig", "bird"};
System.out.println(Arrays.equals(strArr, strArr2));
System.out.println(strArr.equals(strArr2));
System.out.println(strArr == strArr2);

答:上面代码执行的结果,分别为:true、false、false。

题目解析:strArr == strArr2 为引用比较,因此结果一定是 false,而数组本身的比较也就是 strArr.equals(strArr2) 为 false 的原因是因为数组没有重写 equals 方法,因此也是引用比较。数组 equals 源码实现如下:

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

而 Arrays.equals 的结果之所以是 true 是因为 Arrays.equals 重写了 equals 方法。源代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static boolean equals(Object[] a, Object[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++) {
Object o1 = a[i];
Object o2 = a2[i];
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return true;
}

8. 以下程序使用 Arrays.binarySearch 返回的结果是 true 还是 false?

1
2
3
String[] arr = {"dog", "cat", "pig", "bird"};
int result = Arrays.binarySearch(arr, "bird");
System.out.println(result == -1);

答:返回的结果是:true。

题目解析:使用 Arrays.binarySearch 之前一定要先调用 Arrays.sort() 对数组进行排序,否则返回的结果有误,本数组返回的结果是 ﹣1,是因为没有使用排序的结果,正确的使用请查看以下代码:

1
2
3
4
String[] arr = {"dog", "cat", "pig", "bird"};
Arrays.sort(arr);
int result = Arrays.binarySearch(arr, "bird");
System.out.println(result == -1);

9. Arrays 对象有哪些常用的方法?

答:Arrays 常用方法如下:

  • Arrays.copyOf() 数组拷贝
  • Arrays.asList() 数组转为 List 集合
  • Arrays.fill() 数组赋值
  • Arrays.sort() 数组排序
  • Arrays.toString() 数组转字符串
  • Arrays.binarySearch() 二分法查询元素
  • Arrays.equals() 比较两个数组的值

10. 查询字符串数组中是否包含某个值有几种方法?

答:常见查询数组中是否包含某个值有以下两种方式:

  • 方式一:Arrays.asList(array).contains(“key”);
  • 方式二:Arrays.binarySearch(array, “key”);

具体的实现代码如下:

1
2
3
4
5
6
7
8
String[] arr = {"doc", "pig", "cat"};
// 方式一:Arrays.asList(array).contains
boolean bool = Arrays.asList(arr).contains("cat");
System.out.println(bool);
// 方式二:Arrays.binarySearch
Arrays.sort(arr);
boolean bool2 = Arrays.binarySearch(arr, "cat") > -1;
System.out.println(bool2);

11. 如何修改数组的第三个到第五个元素的值为 6?

答:本题考察的知识点显然不是使用 for 循环修改那么简单,而是考察对 Arrays.fill() 方法的掌握,以下提供了两种实现方式可供参考。

方式一:for 循环方式

1
2
3
4
5
6
int[] arrInt = new int[10];
for (int i = 0; i < arrInt.length; i++) {
if (i >= 2 && i < 5) {
arrInt[i] = 6;
}
}

方式二:Arrays.fill() 方式

1
2
int[] arrInt = new int[10];
Arrays.fill(arrInt, 2, 5, 6);

总结

在 Java 中数组本质是引用类型,数组只能用来存储固定大小的同类型元素。在 Java 中很多集合的内部都是依赖数组实现的,如 ArrayList 和 HashMap 等。数组的冒泡排序和选择排序也是面试常考的内容,很多公司会要求面试者手写冒泡排序。本文也介绍了数组、字符串和集合之间的相互转换,只有掌握好这些技能才能开发出更好的 Java 程序。

文章目录
  1. 1. 数组
    1. 1.1. 数组的概述
      1. 1.1.1. 数组的理解
      2. 1.1.2. 数组的特点
      3. 1.1.3. 数组的分类
    2. 1.2. 一维数组的使用
      1. 1.2.1. 一维数组的声明与初始化
      2. 1.2.2. 一维数组元素的引用
      3. 1.2.3. 数组的属性
      4. 1.2.4. 一维数组的遍历
      5. 1.2.5. 一维数组元素的默认初始化值
      6. 1.2.6. 一维数组的内存解析
    3. 1.3. 二维数组
      1. 1.3.1. 如何理解二维数组
      2. 1.3.2. 如何调用二维数组元素
      3. 1.3.3. 二维数组的属性
      4. 1.3.4. 遍历二维数组元素
      5. 1.3.5. 二维数组元素的默认初始化值
    4. 1.4. 数组的常见算法
      1. 1.4.1. 理解
      2. 1.4.2. 使用
        1. 1.4.2.0.1. 数组填充
        2. 1.4.2.0.2. 数组合并
  2. 1.5. 数组的常见异常
  3. 1.6. 数组类型转换
    1. 1.6.0.0.1. 字符串转数组
    2. 1.6.0.0.2. 数组转字符串
    3. 1.6.0.0.3. 数组转集合
    4. 1.6.0.0.4. 集合转数组
  • 1.7. 查找
    1. 1.7.1. 查找算法分类
    2. 1.7.2. 平均查找长度(Average Search Length,ASL)
    3. 1.7.3. 顺序查找
      1. 1.7.3.1. 顺序查找的基本思想
      2. 1.7.3.2. 顺序查找的代码
    4. 1.7.4. 二分查找
      1. 1.7.4.1. 二分查找的基本思想
      2. 1.7.4.2. 二分查找的代码
      3. 1.7.4.3. 1. 数组和集合有什么区别?
      4. 1.7.4.4. 2. 以下代码访问数组元素打印的结果是多少?
      5. 1.7.4.5. 3. 执行以下代码会输出什么结果?
      6. 1.7.4.6. 4. 以下程序打印的结果是多少?
      7. 1.7.4.7. 5. 数组转换字符串有哪些方式?
      8. 1.7.4.8. 6. 数组遍历有哪几种方式?
      9. 1.7.4.9. 7. 以下数组比较的结果分别是什么?
      10. 1.7.4.10. 8. 以下程序使用 Arrays.binarySearch 返回的结果是 true 还是 false?
      11. 1.7.4.11. 9. Arrays 对象有哪些常用的方法?
      12. 1.7.4.12. 10. 查询字符串数组中是否包含某个值有几种方法?
      13. 1.7.4.13. 11. 如何修改数组的第三个到第五个元素的值为 6?
    5. 1.7.5. 总结
  • |