数组
变量存储同一组数据的弊端:
- 命名和书写繁琐
- 使用时的效率低下
概念
是内存中一块连续的存储空间,作用为同时存放多个相同数据类型的值
创建
-
先声明,后指明长度
数据类型 []数组名;//声明 数组名=new 数据类型[长度];//指明长度
int []arr; arr=new int[3];
数据类型 []数组名;
数据类型[] 数组名;
数据类型 数组名[];
- 数组创建时必须指明长度,作用为方便内存分配空间
- 长度必须为整型
-
声明的同时直接指明长度
数据类型[] 数组名=new 数据类型[长度];
int[] arr2 = new int[3];
-
创建的同时直接存放数据
数据类型[] 数组名=new 数据类型[]{值1,值2,..};
int[] arr3=new int[]{10,20,30,40};
- 数组长度由值的个数决定
- 右侧[]中不可再次指明长度
-
创建的同时直接存放数据-简写
数据类型[] 数组名={值1,值2,..};
int[] arr4 = {10, 20, 30};
-
无法先声明,后{}直接赋值
int []arr5; arr5 = {10, 20, 30};//错误! arr5 = new int[]{10, 20, 30};//正确
-
使用
-
通过下标操作数组元素
-
下标从0开始,至数组长度前一位结束
-
通过下标取值赋值:
取值:数组名[下标] 存值:数组名[下标]=值;
-
下标的使用不可超出范围,否则会报出数组下标越界异常
java.lang.ArrayIndexOutOfBoundsException;
-
可以通过
数组名.length
动态获取数组长度
//创建一个长度为3的整型数组
int[] arr = new int[3];
//往下标位置中依次存放数据
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
// arr[3] = 40; java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常
//获取存放数据
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
//创建数组
int[] arr2 = {10, 20, 30, 40};//0-3
//获取数组长度
System.out.println(arr2.length);//4
遍历
依次获取查看数组的数据
for(int i=0;i<数组名.length;i++){
//i代表下标
//通过数组名[i]获取当前正在被遍历的元素值
}
for (int i = 0; i < arr.length; i++) {
//获取当前数组元素
System.out.println(arr[i]);
}
//定义一个长度为5的整型数组并任意赋值
//要求计算数组值之和
//定义数组
int[] arr = {10, 20, 30, 40, 50};
//遍历数组
int sum=0;//累加器
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("sum: "+sum);
//定义一个长度为5的整型数组并任意赋值
//找出数组中最大的值
//定义数组
int[] arr = {11, 23, 56, 17, 45};
int max=0;//接收最大值
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println("最大值为: "+max);
public static void main(String[] args) {
//定义一个整型数组
int[] a = {10, 20, 30, 40, 50};
method1(a);
}
//定义一个函数,传入一个整型数组,要求计算输出数组的平均值
public static void method1(int[] arr){
int sum=0;//累加器
//遍历数组
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println(sum/arr.length);
}
public static void main(String[] args) {
//创建一个整型数组,用来传参
int[] a = {10, 11, 12, 13, 14};
int[] b = method(a);
//查看返回值
for (int i = 0; i < b.length; i++) {
System.out.println(b[i]);
}
}
//定义一个函数,传入一个整型数组a,要求找出a数组中所有的偶数并返回
public static int[] method(int[] a) {
//1. 最上方定义用来返回的数组,并完整创建
//获取a数组中偶数的数量
int num=0;//累加器,接收偶数的数量
//遍历数组a
for (int i = 0; i < a.length; i++) {
//判断当前元素是否为偶数
if (a[i] % 2 == 0) {
num++;
}
}
int[] arr=new int[num];//arr长度为3:0 1 2 {10,12,14}
//2. 在操作过程中给数组进行赋值
int j=0;//表示arr数组下标
//遍历a数组
for (int i = 0; i < a.length; i++) {//a={10,11,12,13,14} 0-4
//判断当前元素是否为偶数
if (a[i] % 2 == 0) {
//将元素放入arr数组进行返回
arr[j]=a[i];//arr[2]=a[4]
j++;//使下标后移,准备做下次赋值
}
}
//3. 最下方返回该数组
return arr;
}
数组高级
深入数组底层
-
数组是引用类型
-
底层存放:栈中存放引用名(数组名),引用名对应堆中的一块空间,堆空间中存放数组的具体信息(值)
-
引用类型之间相互赋值传递的是堆地址
public static void main(String[] args) { int a = 10; int b = a;//基本类型间相互赋值传递的是值 a++;//a+=1; System.out.println("a: "+a);//11 System.out.println("b: "+b);//10 int[] arr1 = {1, 2, 3, 4, 5}; int[] arr2=arr1;//将arr1的堆地址赋值给了arr2 //将arr1下标为0的位置的值改成66 arr1[0] = 66; //将arr2下标为1的位置值改成88 arr2[1] = 88; //查看数组的值 System.out.println("arr1: "); for (int i = 0; i < arr1.length; i++) { System.out.print(arr1[i]+"\t");//66 88 3 4 5 } System.out.println(); System.out.println("arr2: "); for (int i = 0; i < arr2.length; i++) { System.out.print(arr2[i]+"\t");//66 88 3 4 5 } }
-
“逢new必开”:只要执行到new关键字,堆中一定会开辟空间
-
为了保证内存空间的正常分配,数组存在默认值
默认值:是编译器给的,是空间的第一次赋值
初始值:是程序员手动第一次赋值
int : 0
double : 0.0
boolean : false
char : 空
String : null
数组扩容
-
创建一个长度更大的数组(通常为原数组2倍)
-
将原数组的数据复制到新数组中
-
将引用的地址转向新数组
利用for循环
public static void main(String[] args) {
//原数组:整型数组
int a[] = {10, 20, 30, 40, 50};
//需求:将数组a扩容2倍
//1. 创建一个长度为a的2倍的数组
int[] newA=new int[a.length*2];//{10,20,30,40,50,0,0,0,0,0}
//2. 将原数组数据复制到新数组中
//遍历数组a
for (int i = 0; i < a.length; i++) {
//将当前元素的值赋值给新数组
newA[i] = a[i];
}
//3. 将引用的地址转向新数组地址
a = newA;
//查看原数组数据
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
利用arraycopy方法
- System.arraycopy(原数组名,原数组复制起始下标,新数组名,新数组存放起始下标,复制长度)
public static void main(String[] args) {
//原数组:整型数组
int a[] = {10, 20, 30, 40, 50};
//需求:将数组a扩容2倍
//1. 创建一个长度为a的2倍的数组
int[] newA=new int[a.length*2];//{10,20,30,40,50,0,0,0,0,0}
//2. 将原数组数据复制到新数组中
System.arraycopy(a,0,newA,0,a.length);
//3. 将引用的地址转向新数组地址
a = newA;
//查看原数组数据
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
利用copyOf方法
- 新数组地址 java.util.Arrays.copyOf(原数组名,预期的数组长度)
public static void main(String[] args) {
//原数组:整型数组
int a[] = {10, 20, 30, 40, 50};
//需求:将数组a扩容2倍
a=Arrays.copyOf(a, a.length * 2);
//查看原数组数据
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
数组缩容同理
数组排序
冒泡排序
- 让相邻的两个位置进行比较,每轮比较结束之后都会确定一个值(从后往前)
- 实现思路:外层循环代表比较轮数,内层循环代表比较次数
int a[] = {55, 11, 66, 44};
for (int i = 1; i < a.length; i++) {//轮数
for (int j = 0; j < a.length - i; j++) {//次数
//让下一元素和当前元素进行比较
//从小到大:小于号 从大到小:大于号
if (a[j + 1] < a[j]) {
//交换值
int temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}
/*
* 从小到大
* 55, 11, 66, 44
*
*第1轮:
* 第0次:11 55 66 44
* 第1次:11 55 66 44
* 第2次:11 55 44 66
* 第2轮:
* 第0次:11 55 44 66
* 第1次:11 44 55 66
* 第3轮:
* 第0次:11 44 55 66
*
* 1-3
* 2-2
* 3-1
*
*
*
*
* 99 55 77 1
* 第1轮:
* 第1次:55 99 77 1
* 第2次:55 77 99 1
* 第3次:55 77 1 99
* 第2轮:
* 第1次:55 77 1 99
* 第2次:55 1 77 99
* 第3轮:
* 第1次:1 55 77 99
*
*
*
* */
选择排序
- 固定一个下标位置,让其他下标位置与其比较,根据比较结果决定是否换位
- 每轮比较结束后,固定下标位置的值将被确定
- 实现思路:外层循环遍历固定下标,内层循环遍历与其比较的下标
int[] a = {99, 55, 77, 1};
for (int i = 0; i < a.length - 1; i++) {//固定的下标范围
for (int j = i + 1; j < a.length; j++) {//比较的下标
//判断比较位置的值是否小于固定位置的值
//从小到大:小于号 从大到小:大于号
if (a[j] < a[i]) {
//值换位
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
}
}
JDK排序
- java.util.Arrays.sort(数组名):对数组元素进行快速的升序排列
int[] a = {55, 99, 77, 1};
Arrays.sort(a);