数组
1. 数组的概念
概念:一组
连续的存储空间,存储多个相同数据类型的值,长度是固定的。
2. 数组的定义方式
先声明、再分配空间: 数据类型[] 数组名; 数组名 = new 数据类型[长度];
声明并分配空间: 数据类型[] 数组名 = new 数据类型[长度];
声明并赋值(繁): 数据类型[] 数组名 = new 数据类型[]{value1,value2,value3,...};
声明并赋值(简): 数据类型[] 数组名 = {value1,value2,value3,...};
中括号可以书写在数组名之后 但是推荐书写在类型之后 数组名之前
package com.xxx.test2;
/**
* 数组的四种定义方式 中括号可以书写在数组名之后 但是推荐书写在类型之后 数组名之前
* 1.先声明 再分配空间
* 2.声明并且分配空间
* 3.声明并且赋值(繁琐)
* 4.声明并且赋值(简单)
*/
public class TestArrayDefine {
public static void main(String args[]) {
// 1.先声明 再分配空间
int arr1[];
arr1 = new int[3];
// 2.声明并且分配空间
int arr2[] = new int[4];
// 3.声明并且赋值(繁琐) 这种方式可以分开写
int arr3[] = new int[]{11, 23, 444, 666, 777, 234456};
int arr6[];
arr6 = new int[]{12,3,4,5667,777};
// 4.声明并且赋值(简单) 这种方式必须在一行书写完成 不能分开写
int arr4[] = {1, 2, 33, 44, 567};
// int [] arr5;
// arr5 = {1,2,3,4,5};
}
}
3. 数组的使用
数组的使用
元素:数组中的数据称之为元素 Element
下标:角标,索引,英文名称 index 从0开始 往后依次+1
访问 对元素进行存取的操作 称之为访问
取值:System.out.print(数组名[下标])
赋值:数组名[下标] = 值;
访问不存在的下标 会出现:数组下标越界异常 ArrayIndexOutOfBoundsException
异常会导致程序中断 即未执行的代码 不再执行
package com.xxx.test3;
/**
* 数组的使用
* 元素:数组中的数据称之为元素 Element
* 下标:角标,索引,英文名称 index 从0开始 往后依次+1
* 访问 对元素进行存取的操作 称之为访问
* 取值:System.out.print(数组名[下标])
* 赋值:数组名[下标] = 值;
*
* 访问不存在的下标 会出现:数组下标越界异常 ArrayIndexOutOfBoundsException
* 异常会导致程序中断 即未执行的代码 不再执行
*/
public class TestArrayUes {
public static void main(String[] args) {
int [] nums = new int[5];
// 赋值
nums[0] = 11;
nums[1] = 433;
nums[2] = 123;
nums[3] = 444;
nums[4] = 555;
// nums[5] = 666;
// 取值
System.out.println("第一个元素的值为:" + nums[0]);
System.out.println("第二个元素的值为:" + nums[1]);
System.out.println("第三个元素的值为:" + nums[2]);
System.out.println("第四个元素的值为:" + nums[3]);
System.out.println("第五个元素的值为:" + nums[4]);
// System.out.println("第六个元素的值为:" + nums[100]);
}
}
4.数组的遍历
数组的遍历:逐一对数组中元素进行访问
数组的属性:length 是一个int类型的整数 表示数组元素的个数 也就是数组长度
可以通过数组名加点进行使用
数组名.length
JDK提供了关于获取数组元素信息的方法 :Arrays.toString(数组名)
这个方法会将数组中的元素 拼接为字符串 并且使用[]包括起来
package com.xxx.test3;
import java.util.Arrays;
/**
* 数组的遍历:逐一对数组中元素进行访问
*
* 数组的属性:length 是一个int类型的整数 表示数组元素的个数 也就是数组长度
* 可以通过数组名加点进行使用
* 数组名.length
*
* JDK提供了关于获取数组元素信息的方法 :Arrays.toString(数组名)
* 这个方法会将数组中的元素 拼接为字符串 并且使用[]包括起来
*
*
*/
public class TestArrayForeach {
public static void main(String[] args) {
int [] nums = {11,55,88,65,32,789,444,555,1,2,3,555,666,77,888,34,213,24,345,765,243};
System.out.println(nums.length);
for(int i = 0;i < nums.length;i++){
System.out.println("第" + (i + 1) + "个元素的值为:" + nums[i]);
}
String numsStr = Arrays.toString(nums);
System.out.println("numsStr = " + numsStr);
System.out.println("程序结束");
}
}
5. 数组的默认值
数组的默认值
数组作为引用数据类型 其元素是有默认值的 当我们开辟空间以后 默认值即存在
整数:0
小数:0.0
字符:\u0000
布尔:false
其他:null
数组定义在方法内,是否属于局部变量?
依然属于局部变量 凡是定义在方法体内的(形参也是) 都属于局部变量
局部变量没有默认值,为什么数组有默认值呢?
局部变量是指只声明 没有赋值的变量没有默认值
而数组属于 我们赋值以后的默认值 开辟空间 以后的默认值
package com.xxx.test4;
import java.util.Arrays;
/**
* 数组的默认值
* 数组作为引用数据类型 其元素是有默认值的 当我们开辟空间以后 默认值即存在
* 整数:0
* 小数:0.0
* 字符:\u0000
* 布尔:false
* 其他:null
*
* 数组定义在方法内,是否属于局部变量?
* 依然属于局部变量 凡是定义在方法体内的(形参也是) 都属于局部变量
*
* 局部变量没有默认值,为什么数组有默认值呢?
* 局部变量是指只声明 没有赋值的变量没有默认值
* 而数组属于 我们赋值以后的默认值 开辟空间 以后的默认值
*
*/
public class TestArrayDefaultValue {
public static void main(String[] args) {
byte [] a1 = new byte[3];
for(int i = 0;i < a1.length ;i++){
System.out.print(a1[i] + "\t");
}
System.out.println();
short [] a2 = new short[4];
// 打印方法表示打印方法的返回值
System.out.println(Arrays.toString(a2));
int [] a3 = new int[5];
System.out.println(Arrays.toString(a3));
long [] a4 = new long[6];
System.out.println(Arrays.toString(a4));
float [] a5 = new float[1];
System.out.println(Arrays.toString(a5));
double [] a6 = new double[2];
System.out.println(Arrays.toString(a6));
boolean [] a7 = new boolean[3];
System.out.println(Arrays.toString(a7));
char [] a8 = new char[4];
System.out.println(Arrays.toString(a8));
String [] a9 = new String[3];
System.out.println(Arrays.toString(a9));
}
}
6. 数组的扩容
数组的扩容
创建大于原数组长度的新数组。
将原数组中的元素依次复制到新数组中。
将新数组的地址赋值给指向老数组的变量。
package com.xxx.test5;
import java.util.Arrays;
/**
* 数组的扩容
* 创建大于原数组长度的新数组。
* 将原数组中的元素依次复制到新数组中。
* 将新数组的地址赋值给指向老数组的变量。
*/
public class TestArrayGrow {
public static void main(String[] args) {
int [] oldArray = {11,22,33,44,55};
// 创建大于原数组长度的新数组。
int [] newArray = new int[oldArray.length * 2];
// 将原数组中的元素依次复制到新数组中。
for(int i = 0;i < oldArray.length;i++){
newArray[i] = oldArray[i];
}
System.out.println(Arrays.toString(oldArray));
System.out.println(Arrays.toString(newArray));
System.out.println("赋值地址之前原数组的地址:" + oldArray);
System.out.println("赋值地址之前新数组的地址:" + newArray);
// 数组作为引用数据类型 其数组名中保存的是指向堆中的地址值
// 所以 将一个数组赋值给另外一个数组 赋值的是堆中的地址
oldArray = newArray;
System.out.println(oldArray.length);
System.out.println(newArray.length);
System.out.println("赋值地址之后原数组的地址:" + oldArray);
System.out.println("赋值地址之后新数组的地址:" + newArray);
}
}
7. 复制数组的方式
复制数组的三种方式
循环将原数组中所有元素逐一赋值给新数组。
System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);
java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。
package com.xxx.test5;
import java.util.Arrays;
/**
* 复制数组的三种方式
* 循环将原数组中所有元素逐一赋值给新数组。
* System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);
* java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。
*/
public class TestArrayCopy {
public static void main(String[] args) {
int [] arr1 = new int[]{1,2,3,4,5};
int [] arr2 = new int[10];
// 第一个参数 原数组
// 第二个参数 新数组
// 第三个参数 原数组起始位置 0表示第一个
// 第四个参数 新数组起始位置 0表示第一个
// 第五个参数 复制元素的个数
System.arraycopy(arr1,0,arr2,5,5);
System.out.println(Arrays.toString(arr2));
System.out.println("-----------------------------------------");
int [] nums = {12,23,34,45,56};
// 第一个参数 原数组
// 第二个参数 新长度 此方法会返回一个新的数组
int [] newNums = Arrays.copyOf(nums,10);
System.out.println(Arrays.toString(newNums));
}
}
8. 数组练习题
统计int类型数组中所有元素的总和,平均值。
package com.xxx.test5;
import java.util.Scanner;
/**
* 统计int类型数组中所有元素的总和/平均值。
*
* 数组名.for 增强for循环
* 数组名.fori 普通for循环 从前往后遍历
* 数组名.forr 普通for循环 从后往前遍历
*
*/
public class TestArrayExercise1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入一个数组长度");
int length = input.nextInt();
int [] nums = new int[length];
for(int i = 0; i < nums.length; i++){
System.out.println("请输入数组中的第" + (i + 1) + "个元素的值");
nums[i] = input.nextInt();
}
System.out.println("--------------------------------------------------------");
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
System.out.println("总和为:" + sum);
System.out.println("平均值为:" + sum / nums.length);
}
}
9. 数组类型的参数和返回值
数组类型的参数 和 返回值 :使用方式与之前相同
需求:
1.编写方法用于统计一个学生的5门成绩 使用数组作为返回值返回5门成绩
2.编写方法用于计算一个学生5门成绩的平均分
package com.xxx.test6;
import java.util.Scanner;
/**
* 数组类型的参数 和 返回值 :使用方式与之前相同
*
* 需求:
* 1.编写方法用于统计一个学生的5门成绩 使用数组作为返回值返回5门成绩
* 2.编写方法用于计算一个学生5门成绩的平均分
*/
public class TestArrayParamAndReturnedValue {
public static double[] inputScores(){
Scanner input = new Scanner(System.in);
double [] scores = new double[5];
for(int i = 0;i < scores.length;i++){
System.out.println("请输入第" + (i + 1) + "门成绩");
scores[i] = input.nextDouble();
}
return scores;
}
public static void printScoresAvg(double [] scores){
double sum = 0;
for (int i = 0; i < scores.length; i++) {
sum += scores[i];
}
System.out.println("平均分为:" + sum / scores.length);
}
public static void main(String[] args) {
double [] score = inputScores();
printScoresAvg(score);
}
}
10.可变长参数
概念:可变长参数 可接收多个同类型实参,个数不限,使用方式与数组相同。
语法:数据类型... 形参名
要求:必须定义在形参列表的最后,且只能有一个。
package com.xxx.test6;
/**
* 概念:可变长参数 可接收多个同类型实参,个数不限,使用方式与数组相同。
* 语法:数据类型... 形参名
* 要求:必须定义在形参列表的最后,且只能有一个。
*/
public class TestChangeableParam {
public static void m1(int [] arr1){
System.out.println("m1方法开始执行");
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("m1方法开始执行");
}
public static void m2(int a, int... arr1){
System.out.println("m2方法开始执行");
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("m2方法执行完毕");
}
public static void main(String[] args) {
int [] arr1 = {};
m1(arr1);
m2(1,11,333,444);
}
}
11. 值传递和引用传递的区别
数组面试题 : 值传递和引用传递的区别 ?
基本数据类型传参 传递的是值的副本(拷贝) 属于将值复制了一份 传给了形参 称之为值传递
引用数据类型传参 传递的是内存中的地址值 属于引用(地址值)传递
Java官方明确说明 Java中是没有所谓的 “引用传递” 只有值传递
package com.xxx.test6;
import java.util.Arrays;
/**
* 数组面试题 : 值传递和引用传递的区别 ?
*
* 基本数据类型传参 传递的是值的副本(拷贝) 属于将值复制了一份 传给了形参 称之为值传递
*
* 引用数据类型传参 传递的是内存中的地址值 属于引用(地址值)传递
*
* Java官方明确说明 Java中是没有所谓的 “引用传递” 只有值传递
*/
public class TestArrayInterview {
public static void m1(int num){
num++;
System.out.println("num = " + num); // 11
}
public static void m2(int [] nums){
System.out.println("nums = " + nums);
for (int i = 0; i < nums.length; i++) {
nums[i] = 666;
}
System.out.println("nums = " + Arrays.toString(nums));
}
public static void main(String[] args) {
int a = 10;
m1(a);
System.out.println("a = " + a); // 10
int [] arr = {1,2,3,4,5};
System.out.println("arr = " + arr);
m2(arr);
System.out.println("arr = " + Arrays.toString(arr));
}
}
12. 冒泡排序
冒泡排序
外层循环 行 比较的轮数:n - 1
内层循环 列 每一轮比较的次数 : n - 1 - i
package com.xxx.test7;
import java.util.Arrays;
/**
* 冒泡排序
* 外层循环 行 比较的轮数:n - 1
* 内层循环 列 每一轮比较的次数 : n - 1 - i
*/
public class TestBubbleSort {
public static void main(String[] args) {
int [] nums = {5,4,3,2,1,0};
for(int i = 0;i < nums.length - 1;i++){
for(int j = 0;j < nums.length - 1 - i;j++){
if(nums[j] < nums[j + 1]){
flag = false;
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
System.out.println("第" + (i + 1) + "轮比较完成以后元素的顺序为:" + Arrays.toString(nums));
}
System.out.println(Arrays.toString(nums));
}
}
13.冒泡排序优化
因为冒泡排序 如果顺序不正确 则会立即交换元素的位置
所以 如果本轮没有交换元素的位置 则可以判定为 元素已经排列正确
则可以提前结束循环
package com.xxx.test7;
import java.util.Arrays;
/**
* 冒泡排序
* 外层循环 行 比较的轮数:n - 1
* 内层循环 列 每一轮比较的次数 : n - 1 - i
*/
public class TestBubbleSort {
public static void main(String[] args) {
int [] nums = {5,4,3,2,1,0};
for(int i = 0;i < nums.length - 1;i++){
boolean flag = true; // 每一轮开始 表示初始值都为true
for(int j = 0;j < nums.length - 1 - i;j++){
if(nums[j] < nums[j + 1]){
flag = false;
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
System.out.println("第" + (i + 1) + "轮比较完成以后元素的顺序为:" + Arrays.toString(nums));
if(flag){ // 本轮比较完成 标记依然为true 则表示本轮未交换任何元素的位置
break; // 则表示可以直接结束循环 即后续的轮次不用比较了
}
}
System.out.println(Arrays.toString(nums));
}
}
14. 选择排序
选择排序 : 固定(位置)元素与其他元素依次比较大小,遇到需要交换位置的元素,
不立即交换位置,使用新的元素继续往后比较,等待一轮比较完成,交换一次位置。
选择排序我们可以理解为两个元素进行比较 假设为 A 和 B
元素A 从第一个位置开始 直到倒数第二个 位置 A 0 ~ n - 1
元素B 从A元素之后相邻的位置开始 直到最后一个 位置 B A + 1 ~ n
可以用外层循环 表示元素A
内存循环表示 元素B
package com.xxx.test1;
import java.util.Arrays;
/**
* 选择排序 : 固定(位置)元素与其他元素依次比较大小,遇到需要交换位置的元素,
* 不立即交换位置,使用新的元素继续往后比较,等待一轮比较完成,交换一次位置。
*
*
* 选择排序我们可以理解为两个元素进行比较 假设为 A 和 B
* 元素A 从第一个位置开始 直到倒数第二个 位置 A 0 ~ n - 1
* 元素B 从A元素之后相邻的位置开始 直到最后一个 位置 B A + 1 ~ n
*
* 可以用外层循环 表示元素A
* 内存循环表示 元素B
*
*
*
*
*/
public class TestSelectionSort {
public static void main(String[] args) {
int [] nums = {-1,11,32,4,56,777,86,234};
for(int a = 0;a < nums.length - 1;a++){
int index = a; // 每次开始一轮新的比较 将当前元素a的下标 记录下来 赋值给index
for(int b = a + 1 ;b < nums.length ;b++){
if(nums[index] > nums[b]){
index = b;
}
}
if(a != index){
int temp = nums[a];
nums[a] = nums[index];
nums[index] = temp;
}
System.out.println("第" + (a + 1) + "轮比较完成以后元素的顺序为:" + Arrays.toString(nums));
}
System.out.println(Arrays.toString(nums));
}
}
15. JDK提供的快速排序
JDK提供的快速排序:Arrays.sort() 升序
package com.xxx.test1;
import java.util.Arrays;
/**
* JDK提供的快速排序:Arrays.sort() 升序
*/
public class TestArraysSort {
public static void main(String[] args) {
int [] nums = {-1,11,32,4,56,777,86,234};
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
System.out.println("*********************将升序改为降序方式1*********************");
int [] arr1 = new int[nums.length];
for(int i = 0,j = nums.length - 1;i < nums.length;i++,j--){
arr1[j] = nums[i];
}
System.out.println(Arrays.toString(arr1));
System.out.println("*********************将升序改为降序方式2*********************");
for(int i = 0; i < nums.length / 2;i++){
int temp = nums[i];
nums[i] = nums[nums.length - 1 - i];
nums[nums.length - 1 - i] = temp;
}
System.out.println(Arrays.toString(nums));
}
}
16. 复杂度
17. 二维数组
概念:一维数组中的一维数组;数组中的元素,还是数组。
package com.xxx.test2;
/**
* 二维数组 :数组中的元素还是数组
*/
public class Test2DArray1 {
public static void main(String[] args) {
int [] arr1 = {1,2,3,4};
int [][] arr2 = {{11,22} , {123,345,567,777} , {22,55,88} };
System.out.println(arr2[0]);
System.out.println(arr2[0][0]);
System.out.println(arr2[0][1]);
System.out.println(arr2[1]);
System.out.println(arr2[1][0]);
System.out.println(arr2[1][1]);
System.out.println(arr2[1][2]);
System.out.println(arr2[1][3]);
System.out.println(arr2[2]);
System.out.println(arr2[2][0]);
System.out.println(arr2[2][1]);
System.out.println(arr2[2][2]);
System.out.println("----------------------------------------");
for(int i = 0;i < arr2.length;i++){
for(int j = 0;j < arr2[i].length;j++){
System.out.print(arr2[i][j]+ "\t");
}
System.out.println();
}
}
}
二维数组的创建
创建二维数组,高维度(第一个中括号)的长度必须直接书写,低维度(第二个中括号)的长度可以直接书写,也可以分开书写。
数组的默认值问题:
对于二维数组,其每个元素为一维数组,所以默认值为null
所以必须先开辟一维数组的空间 才可以存放数据 否则将出现空指针异常
NullPointerException NPE
package com.xxx.test2;
/**
* 二维数组的创建
* 创建二维数组,高维度(第一个中括号)的长度必须直接书写,低维度(第二个中括号)的长度可以直接书写,也可以分开书写。
*
* 数组的默认值问题:
*
* 对于二维数组,其每个元素为一维数组,所以默认值为null
* 所以必须先开辟一维数组的空间 才可以存放数据 否则将出现空指针异常
* NullPointerException NPE
*
*
*/
public class Test2DArray2 {
public static void main(String[] args) {
int [] nums = new int[3];
// 方式1 先声明 再分配空间
int [][] arr1;
arr1 = new int[4][];
System.out.println(arr1[0]);
arr1[0] = new int[2];
arr1[0][0] = 11;
arr1[0][1] = 12;
System.out.println(arr1[1]);
arr1[1] = new int[]{11,22,33,44};
System.out.println(arr1[2]);
int [] array = {1,2,3,4,5};
arr1[2] = array;
System.out.println(arr1[3]);
arr1[3] = new int[]{1,2,3,4,5};
// 方式2 声明并且分配空间
int [][] arr2 = new int[2][3];
// 方式3 声明并且赋值 繁琐的方式
int [][] arr3 = new int[][]{{11,22},{123,345,567,666},{1,2,3,4,5}};
// 方式4 声明并且赋值 简单的方式
int [][] arr4 = {{11,22},{123,345,567,666},{1,2,3,4,5}};
}
}