数组
1 数组概述
-
Java语言中的数组是一种引用类型。不属于基本数据类型。数组的父类是Object。
-
数组实际上是一个容器,可以同时容纳多个元素。(数组是一个数据的集合。) 数组:字面意思是”一组数据“。
-
数组当中可以存储”基本数据类型“的数据,也可以存储”引用类型“的数据。
-
数组因为是引用类型,所以数组对象是堆内存当中。(数组是存储在堆当中的)。
-
数组当中如果存储的是”Java对象“的话,实际上存储的是对象的”引用(内存地址)“。
-
数组一旦创建,在Java中规定,长度不可变。(数组长度不可变)。
-
数组的分类:一维数组、二维数组、三维数组、多维数组…
-
所有的数组对象都有length属性,用来获取数组中元素的个数。
-
Java中的数组要求数组中的元素类型统一。
-
数组在内存方面存储的时候,数组中的元素内存地址是连续的。
-
数组中首元素的内存地址作为整个数组对象的内存地址。
-
数组这种数据结构的优点和缺点是什么?
优点:查询/查找/检索某个下标的元素时效率极高。可以说是查询效率最高的一个数据结构。
为什么检索效率高?
-
每个元素的内存地址在空间存储上是连续的。
-
每个元素的类型相同,所以占用空间大小一样。
-
知道第一个元素内存地址,知道每个元素占用空间的大小,又知道下标,所以通过一个数字表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率是最高的。
数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,因为数组中元素查找的时候不会一个一个找个,是通过数学表达式计算出来的。(算出一个内存地址,直接定位的。)
缺点:
第一:由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或增加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作
第二:数组不能存储大数据量,为什么?
因为很难在内存空间上找到一块特别大的连续的内存空间。
注意:对于数组中最后一个元素的增删,是没有效率影响的。
-
2 一维数组
2.1 怎么初始化一个一维数组?
两种方式:静态初始化、动态初始化
2.1.1 静态初始化
//静态初始化语法格式:
int [] array = {10,20,300,40};
//动态初始化语法格式:
int [] array = new int[5];//这里的5表示数组的元素个数。
//初始化一个5个长度的int类型数组,每个元素默认值为0
String [] str = new String[6]; //初始化6个长度的String类型数组,每个元素默认值为null。
示例:数组的存取操作
/**
* @author wcs
* @date 2021/7/30 21:09
*/
public class ArrayTest01 {
public static void main(String[] args) {
int[] a = {1,23,54,56,76};
//取(读)
System.out.println("数组的第一个元素"+a[0]);
System.out.println("数组的最后一个元素"+a[4]);
System.out.println("数组的最后一个元素"+a[a.length-1]);
//存(改)
a[0] = 99;
a[a.length-1] = 0;
System.out.println("数组的第一个元素"+a[0]);
System.out.println("数组的最后一个元素"+a[a.length-1]);
}
}
运行结果:

一维数组遍历
/**
* @author wcs
* @date 2021/7/31 9:39
*/
public class ArrayTest02 {
public static void main(String[] args) {
int[] a = {12,23,45,67,875};
//循环遍历输出
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
//5超过了数组元素总个数,下标越界,出现异常。
// System.out.println(a[5]);//ArrayIndexOutOfBoundsException(下标越界异常)
//反向遍历输出
for (int i = a.length-1; i >= 0; i--) {
System.out.println(a[i]);
}
}
}
2.1.2 动态初始化
/**
* @author wcs
* @date 2021/7/31 9:57
*/
public class ArrayTest03 {
public static void main(String[] args) {
//动态初始化
//int类型数组元素默认值为0
int[] a = new int[4];
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
//引用数据类型数组默认值为null
String [] str = new String[4];
for (int i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
Object[] obj = new Object[4];
for (int i = 0; i < obj.length; i++) {
System.out.println(obj[i]);
}
//静态初始化Object类型数组
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = new Object();
Object[] objs ={obj1,obj2,obj3};
for (int i = 0; i < objs.length; i++) {
System.out.println(objs[i]);
}
}
}
2.1.3 什么时候用静态初始化方式,什么时候用动态初始化方式?
当你创建数组的时候,确定数组中存储哪些具体元素时,采用静态初始化方式。
当你创建数组的时候,不确定将来数组中存储哪些数据,你可以采用动态初始化方式,预先分配内存。
当一个方法的参数是一个数组的时候
/**
* @author wcs
* @date 2021/7/31 10:21
*/
public class ArrayTest04 {
public static void main(String[] args) {
//静态初始化一维数组
int[] a = {1,23,45,27};
printArray(a);
// printArray({1,2,45,6}); //错误写法
//如果直接传递一个静态数组的话,必须这样写
printArray( new int[]{0, 23, 45, 68});
//动态初始化一维数组
int[] a2 = new int[4];
printArray(a2);
System.out.println("-------------");
printArray(new int[4]);//也可以这样写
}
public static void printArray(int[] array){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
2.2 main方法中的String数组
main方法上面的"String[] args"有什么用?
谁负责调用main方法(JVM),JVM调用main方法的时候,会自动传一个String数组过来。JVM给传递过来的String数组参数,这个数组的长度是0。 args不是null。
String[] strs = {};//静态初始化数组,里面没东西。
System.out.println(str.Length);//0
2.2.1 main方法中String数组案例
/**
* @author wcs
* @date 2021/8/4 10:46
*/
public class ArrayTest05 {
//在run下面的Edit Configurations中Program arguments输入用户名和密码
//用户名和密码输入到String[] args数组当中。
public static void main(String[] args) {
if (args.length != 2){
System.out.println("请输入用户名和密码");
return;
}
//执行到此说明用户已经输入了用户名或密码。
//取出判断
String username = args[0];
String password = args[1];
//if(username.equals("admin"))之所以没有这样写是为了防止空指针异常。
if ("admin".equals(username) && "123".equals(password)){
System.out.println("欢迎您 "+username);
}else {
System.out.println("用户名或密码错误");
}
}
}
2.3 数组扩容
在Java程序中,数组长度一旦确定不可变,那么数组满了怎么办?
数组满了,需要扩容。
数组的扩容是:先建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组当中。
数组扩容效率较低。尽量避免数组扩容,可以在创建数组的时候预估计容量。
2.4 数组拷贝
//System.arraycopy(5个参数);
//拷贝源,源起始位置下标,拷贝目标,目标的起始下标,拷贝长度。
示例:
import java.util.Arrays;
/**
* @author wcs
* @date 2021/8/4 14:53
*/
public class ArrayTest06 {
public static void main(String[] args) {
int[] a = {1, 34, 56, 78, 4};
int[] b = new int[10];
//从数组a下标为1的位置开始拷贝到数组b下标为2的位置,共拷贝4个元素。
System.arraycopy(a, 1, b, 2, 4);
for (int i = 0; i < b.length; i++) {
System.out.println(b[i]);
}
}
}
运行结果:

3 二维数组
二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组。
int[] a = {1,23,4};
int[] b = {34,578,5};
int[] c = {56,8,4,2};
//二维数组 静态初始化
int[][] aa = {{1,23,4},{34,578,5},{56,8,4,2}};
//动态初始化
int[][] bb = new int[2][3];
3.1 二维数组的Length属性
public class ArrayTest07 {
public static void main(String[] args) {
int[][] aa = {{1,23},{34,578,5},{56,8,4,2}};
System.out.println(aa.length);//3
System.out.println(aa[0].length);//2
System.out.println(aa[2].length);//4
}
}
3.2 关于二维数组中元素的读和改
/**
* @author wcs
* @date 2021/8/4 16:04
*/
public class ArrayTest08 {
public static void main(String[] args) {
int[][] aa = {{1,23},{34,578,5},{56,8,4,2}};
//取出第一个一维数组
int[] a = aa[0];
//取出第一个一维数组中的第一个元素
int x = a[0];
System.out.println(x);//1
//合并以上代码
System.out.println(aa[0][0]);//1
//改
aa[0][0] = 1111;
System.out.println(aa[0][0]);
}
}
3.3 遍历二维数组
/**
* @author wcs
* @date 2021/8/4 16:12
*/
public class ArrayTest09 {
public static void main(String[] args) {
String[][] strs = {
{"张三","李四","王二"},
{"Java","php","c++"},
{"Jack","rose","okk"}
};
//遍历二维数组
for (int i = 0; i < strs.length; i++) {
//一层循环二维数组里面的一维数组
String[] str1 = strs[i];
//二层循环一维数组中的元素
for (int j = 0; j < str1.length; j++) {
System.out.print(str1[j]+" ");
}
System.out.println();//换行
}
//合并代码
for (int i = 0; i < strs.length; i++) {
for (int j = 0; j < strs[i].length; j++) {
System.out.print(strs[i][j]+" ");
}
System.out.println();
}
}
}
4 Array工具类
4.1 sort()
import java.util.Arrays;
/**
* @author wcs
* @date 2021/8/4 16:30
*/
public class ArrayTest10 {
public static void main(String[] args) {
//工具类当中的方法大部分都是静态的
int[] arr = {23, 47, 223, 112, 34, 5};
Arrays.sort(arr);//升序
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
4.2 fill()
import java.util.Arrays;
/**
* @author wcs
* @date 2021/8/4 20:44
*/
public class ArrayTest13 {
public static void main(String[] args) {
int[] a = new int[10];
Arrays.fill(a, 11);
System.out.println(Arrays.toString(a));
//填充数组,从哪个下标开始,到哪个下标位置,填充数据
Arrays.fill(a, 3, 8, 4);
System.out.println(Arrays.toString(a));
}
}
4.3 比较数组
import java.util.Arrays;
/**
* @author wcs
* @date 2021/8/4 20:51
*/
public class ArrayTest14 {
public static void main(String[] args) {
String[] str1 = {"Java", "php", "c++"};
String[] str2 = {"Java", "php", "c++"};
System.out.println(Arrays.equals(str1, str2));//true
}
}
4.4 数组转字符串
//一维数组
int[] a = {2,43,21,33,29};
//数组转字符串
System.out.println(Arrays.toString(a));//[2, 43, 21, 33, 29]
//多维数组
int[][][] b = {
{{23, 1, 34, 2}},
{{44, 55, 66}},
{{99, 0, 54, 28}},
{{17, 98, 45}}
};
System.out.println(Arrays.deepToString(b));
//[[[23, 1, 34, 2]], [[44, 55, 66]], [[99, 0, 54, 28]], [[17, 98, 45]]]
5 冒泡排序
import java.util.Arrays;
/**
* @author wcs
* @date 2021/8/4 20:07
*/
/**
* 冒泡排序,
* 由小到大
* 从前向后两两比较,如果前面的数大于后面的数就交换
* 如果有n个数,需要比较n-1轮
*/
public class ArrayTest11 {
public static void main(String[] args) {
int[] a = {2, 32, 11, 34, 0, 27};
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
System.out.println(Arrays.toString(a));
}
}
}
}