数组
基本使用
概念
概念:一组
连续
的存储空间,存储多个相同
数据类型的值,长度是固定
的。
定义
方式1:先声明、再分配空间
数据类型[] 数组名;
数组名 = new 数据类型[长度];
方式2:声明并分配空间:
数据类型[] 数组名 = new 数据类型[长度];
方式3:声明并赋值(繁):
数据类型[] 数组名 = new 数据类型[]{value1,value2,value3,...};
方式4:声明并赋值(简):
数据类型[] 数组名 = {value1,value2,value3,...};
package com.yuluo;
public class ArrayTrain {
public static void main(String[] args) {
String [] userNameArr = new String[3];
int [] ageArr = new int[3];
// 赋值
ageArr[0] = 18;
userNameArr[0] = "Hanser";
// 取值
System.out.println("年龄为:"+ageArr[0]);
System.out.println("姓名为:"+userNameArr[0]);
}
}
使用
数组的元素:数组中的每个数据称之为数组中的元素
数组的访问:对数组中的元素赋值以及取值的操作 统称为数组的访问
下标、索引、角标、index : 下标自动生成 从0开始 往后依次+1
访问数组通过下标访问:
赋值 数组名[下标] = 值;
取值 System.out.println(数组名[下标]);
访问不存在的下标 将会导致数组下标越界异常 ArrayIndexOutOfBoundsException
package com.yuluo;
public class ArrayTrain {
public static void main(String[] args) {
String [] userNameArr = new String[3];
int [] ageArr = new int[3];
// 赋值
ageArr[0] = 18;
userNameArr[0] = "Hanser";
// 取值
System.out.println("年龄为:"+ageArr[0]);
System.out.println("姓名为:"+userNameArr[0]);
}
}
遍历
数组的遍历:逐一对数组中的元素进行访问 称之为数组的遍历
package com.yuluo;
public class ArrayTrain {
public static void main(String[] args) {
// 定义一个数组
int[] age;
age = new int[3];
// 数组的遍历
for (int i = 0; i < age.length; i++) {
// 赋值
age[i] = i;
}
// 数组遍历
for (int i = 0; i < age.length; i++) {
System.out.println(age[i]);
}
}
}
默认值
数组的默认值:数组作为引用数据类型 其元素是有默认值的 当我们给数组开辟空间以后 默认值即存在
整数:0
浮点:0.0
字符:\u0000
布尔:false
其他:null (空)
package com.yuluo;
import java.util.Arrays;
public class ArrayTrain {
public static void main(String[] args) {
// 定义一个数组
int[] age = new int[3];
byte[] sex = new byte[2];
float [] salary = new float[3];
boolean [] leader = new boolean[2];
String [] name = new String[2];
char [] marriage= new char[2];
// 把数组转为String
String ageStr = Arrays.toString(age);
String sexStr = Arrays.toString(sex);
String leaderStr = Arrays.toString(leader);
String nameStr = Arrays.toString(name);
String salaryStr = Arrays.toString(salary);
String marriageStr = Arrays.toString(marriage);
// 打印String
System.out.println(ageStr); // [0, 0, 0]
System.out.println(sexStr); // [0, 0]
System.out.println(salaryStr); // [0.0, 0.0, 0.0]
System.out.println(marriageStr); // /u0000
System.out.println(leaderStr); // [false, false]
System.out.println(nameStr); // [null, null]
}
}
使用一个为null的对象,调用任何属性或者方法,都将出现空指针异常
扩容
背景:创建数组时,必须显式指定长度,并在创建之后不可更改长度。
数组的扩容
实现步骤:
1.创建比原数组更长的新数组
2.将原数组中的元素依次复制到新数组中
3.将新数组的地址赋值给原数组
注意:
数组作为引用数据类型 其数组名中保存的是指向堆中的地址
所以 当我们把一个数组 赋值 给 另外一个数组时
赋值的是堆地址
默认打印数组本身得到的是一个内存中的堆地址
package com.yuluo;
import java.util.Arrays;
public class ArrayTrain {
public static void main(String[] args) {
// 数组扩容
int [] oldArr = {15,16,17,18};
// 创建比之前大的新数组
int [] newArr = new int [oldArr.length * 2];
// 复制新数组
for (int i = 0; i < oldArr.length; i++) {
newArr[i] = oldArr[i];
}
// 地址替换
oldArr = newArr;
// 设置新数组
newArr[7] = 28;
System.out.println(oldArr);// [I@4554617c
System.out.println(newArr); // [I@4554617c
System.out.println(Arrays.toString(newArr)); // [15, 16, 17, 18, 0, 0, 0, 28]
}
}
复制
复制数组的三种方式:
循环将原数组中所有元素逐一赋值给新数组。
System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度)
; 无返回值
java.util.Arrays.copyOf(原数组, 新长度)
; 有返回值,返回带有原值的新数组。
package com.yuluo;
import java.util.Arrays;
public class copyArray {
public static void main(String[] args) {
int [] oldArr = {12,13,14,15};
int [] newArr = new int[10];
int [] ageArr = {13,13,13};
// 1. 使用 System.arraycopy 方法
// 参数为 旧数组 下标 新数组 下标 长度
// 无返回值
System.arraycopy(oldArr,1,newArr,2,2);
System.out.println("新数组为 " + Arrays.toString(newArr));
// 2. 使用 Arrays.copyOf 方法
// 有返回值
int [] newAgeArr = Arrays.copyOf(ageArr,10);
System.out.println("新数组1为 " + Arrays.toString(newAgeArr));
}
}
数组方法
JDK提供了一个用于操作数组的工具类 java.util.Arrays
,此类中提供大量的用于操作数组的各种方法
类的方法 类似JS中类本身的方法
Arrays.toString(数组名) : 将数组中的元素转换为字符串 返回
Arrays.copyOf(数组名,新长度) : 复制数组,存在返回值
Arrays.sort(数组名) : 将数组按照升序排序 属于快速排序 实现原理为 递归
Arrays.fill(数组名,填充元素) : 将数组按照指定元素进行填充
Arrays.binarySearch(数组名,元素) : 使用二分查找法查找某个元素在数组中的下标(前提是数组是升序排序后的,且元素不重复),返回值为下标
案例
package com.yuluo;
import java.util.Arrays;
public class utilsArray {
public static void main(String[] args) {
int [] nums = {56,12,22,41,85,99};
// 使用 sort方法排序:快速排序 默认是升序
Arrays.sort(nums);
System.out.println(Arrays.toString(nums)); // [12, 22, 41, 56, 85, 99]
int [] newArr = new int[nums.length];
// 降序排序
for (int i = 0,j = nums.length -1; i < nums.length; i++,j--) {
newArr[i] = nums[j];
}
System.out.println(Arrays.toString(newArr)); // [99, 85, 56, 41, 22, 12]
// 填充元素
Arrays.fill(newArr,445);
System.out.println(Arrays.toString(newArr)); // [445, 445, 445, 445, 445, 445]
// 查找元素
int index = Arrays.binarySearch(nums, 41);
System.out.println("查找到的下标为"+index); // 查找到的下标为 2
}
}
数组属性
数组的属性:length属性 表示数组的长度 是一个int类型的整数 可以通过数组名.length获取
类似于JS中 实例的方法
arr.length 返回数组的长度
package com.yuluo;
public class ArrayTrain {
public static void main(String[] args) {
// 定义一个数组
int[] age;
age = new int[3];
// 数组的遍历
for (int i = 0; i < age.length; i++) {
// 赋值
age[i] = i;
}
}
}
插入(删除)元素
可以使用System.arraycopy
方法 实现插入效果
案例:编写方法实现在数组中删除元素
public class delArrayEle {
public static void main(String[] args) {
int [] nums = {1,2,3,4,5};
// 调用删除方法 删除下标 为2
int[] delete = delete(nums,2);
System.out.println(Arrays.toString(delete));
}
// 删除元素 旧数组 下标
public static int[] delete(int[] oldArray, int index) {
if (index < 0 || index > oldArray.length) {
// 判断下标 如果小于0 或者 大于等于数组长度 表示不合法 因为删除 只能删除有效范围以内的
System.out.println("下标非法");
return oldArray; // 直接将传入的原数组返回 表示没有做任何操作
}
// 准备一个长度-1的数组 用于删除之后复制元素
int[] newArray = new int[oldArray.length - 1];
// 循环遍历开始复制元素
for (int i = 0; i < newArray.length; i++) {
if (i < index) { // 情况1 小于删除的下标 直接复制
newArray[i] = oldArray[i];
} else { // 情况2 大于等于删除下标 则直接将原数组的+1位置 移动到新数组的后续位置 属于向左移动覆盖
newArray[i] = oldArray[i + 1];
}
}
return newArray; // 将新数组返回
}
}
案例:编写方法实现在数组中插入元素
package com.yuluo;
import java.util.Arrays;
public class insertArrayEle {
public static void main(String[] args) {
int [] nums = {1,2,3,4,5};
// 方法
int[] newArray = insertArray(nums, 2,18);
System.out.print(Arrays.toString(newArray));
}
// 插入元素的方法
public static int[] insertArray(int [] oldArrays,int index,int val){
// 下标不能小于0 或者 不能大于数组的长度
if(index < 0 || index > oldArrays.length){
System.out.println("下标不合法");
// 如果下标不合法 则将传入的数组 直接返回 表示没有做任何操作
return oldArrays;
}
// 准备一个长度+1的数组 用于插入元素
int [] newArray = new int[oldArrays.length + 1];
// 遍历开始移动元素
for(int i = 0;i < oldArrays.length;i++){
// 情况1 小于插入下标 则直接复制到新数组中
if(i < index){
newArray[i] = oldArrays[i];
}else{ // 情况2 大于或者等于插入下标 则移动到新数组的+1位置
newArray[i + 1] = oldArrays[i];
}
}
// 空缺位插入指定的元素
newArray[index] = val;
return newArray; // 将新数组返回
}
}
可变长参数
可变长参数:可接收多个同类型实参,个数不限,使用方式与数组相同。
要求:
1.整个形参列表中只能有一个可变长参数
2.必须书写在形参列表的末尾
格式:数据类型...参数名
底层实现是数组
package com.yuluo;
public class ChangeAbleParams {
// 可变长参数
public static void funChangeParams (int ... args) {
System.out.println("fun方法执行");
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
// 数组类型的参数
public static void funArrayTypeParams(int [] args){
System.out.println("funArray方法执行");
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
public static void main(String[] args) {
// 第一个方法调用
funChangeParams(12,13,14,15);
// 第二个方法调用
int [] nums = {13,14,15,16};
funArrayTypeParams(nums);
}
}
数组应用
冒泡排序(写)
它重复地遍历要排序的数组,比较相邻的元素,并交换它们的位置,直到整个数组有序为止。
数组的数量:n
比较的轮数为:n - 1
每一轮比较的次数:n - 1 - ?
外层循环控制比较的轮数:n - 1
内存循环控制每一轮比较的次数:n - 1 - i
package com.yuluo;
public class ShortArray {
public static void main(String[] args) {
int [] arr = {64, 34, 25, 12, 22, 11, 90};
System.out.println("排序前的数组:");
printArray(arr);
// 排序
Bubble(arr);
// 打印排序后的数组
System.out.println("排序后的数组:");
printArray(arr);
}
// 冒泡排序
public static void Bubble(int [] arr){
int length = arr.length;
boolean swapped;
for(int i = 0;i < length -1;i++){
swapped = false;
for(int j = 0; j< length -1 -i;j++){
if(arr[j]>arr[j+1]){
// 交换 arr[j] 和 arr[j+1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
// 如果没有发生交换
if(!swapped){
break;
}
}
}
// 打印数组
public static void printArray(int[] arr) {
for (int i :arr){
System.out.print(i+" ");
}
System.out.println();
}
}
选择排序
固定值与其他值依次比较大小,互换位置。
选择排序:固定位置的元素与其他元素依次比较大小,遇到需要交换位置的元素,先不交换,使用应该被交换位置的元素继续往后比较,等待一轮比较完成,统一交换一次位置。
数组的数量:n
比较的轮数为:n - 1
每一轮比较的次数:最多的一次为n - 1 后续每一轮递减1
将外层循环作为比较的元素A 从第一个元素开始 到 倒数第二个元素
将内层循环作为比较的元素B 从第二个元素开始 到 最后一个元素(即每一轮都是从比较的元素A 紧邻的后边的位置开始)
选择排序每一轮最多只会交换一次位置 所以即使每一轮都交换位置 也最多交换长度的减1次 因为轮数为长度的减1轮
package com.yuluo;
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] nums = {-2, 562, -1, 451, 110, 23, 45, 85, 96, 666};
int count = 0;
int length = nums.length;
for (int i = 0; i < length - 1; i++) { // A
int index = i; // 定义moveIndex 表示为需要最终交换位置的下标
for (int j = i + 1; j < length; j++) { // B
if (nums[index] > nums[j]) {
// 如果A > B,把J的下标赋值给index,拿着B去找下一个B比较,直到这一轮比较结束
index = j;
}
}
// 如果moveIndex 和 i的值不相同 则表示需要交换元素
// 因为 只有比较大小的条件成立 moveIndex的值 才会发生变化
// 而条件成立 则表示有需要交换位置的元素
// 最终将moveIndex 和 i 对应位置的元素进行交换 因为
// i 表示每一轮的第一个元素 而moveIndex最终将停留在最大/最小的元素
if (index != i) {
int temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
count++;
}
}
System.out.println(Arrays.toString(nums));
System.out.println("一共交换了" + count + "次位置");
}
}
数组平均值
package com.yuluo;
import java.util.Scanner;
public class ArrayTypeParams {
public static void main(String[] args) {
// 统计int类型数组中的所有元素总和 平均值
Scanner input = new Scanner(System.in);
System.out.println("输入数组的长度");
// 输入
int length = input.nextInt();
// 创建数组
int [] nums = new int[length];
// 定义sum
int sum = 0;
for (int i = 0; i < nums.length; i++) {
System.out.println("请输入第"+ ( i + 1)+ "个元素");
// 输入元素
nums[i] = input.nextInt();
// 做累加计算
sum += nums[i];
}
// 打印输出
System.out.println("数组的总和为"+sum);
System.out.println("数组的平均值为"+sum/nums.length);
}
}
数组最值
// 分析:先假设一个最大值/最小值 依次与其他元素进行比较 如果遇到更大的/更小的 就交换
package com.yuluo;
import java.util.Scanner;
public class ArrayTypeParams {
public static void main(String[] args) {
// 数组最值问题
// 分析:先假设一个最大值/最小值 依次与其他元素进行比较 如果遇到更大的/更小的 就交换
Scanner input = new Scanner(System.in);
System.out.println("输入数组长度");
int length = input.nextInt();
int [] numArr = new int[length];
// 输入数组元素
for (int i = 0; i < numArr.length; i++) {
System.out.println("输入第"+(i+1)+"个数组元素");
numArr[i] = input.nextInt();
}
// 假设第一个为最大值
int max = numArr[0];
int min = numArr[0];
for (int i = 1; i < numArr.length; i++) {
// 比较最大值
if(numArr[i] > max){
// 如果大于最大值,则替换最大值
max = numArr[i];
}
// 比较最小值
if(numArr[i] < min){
// 如果大于最大值,则替换最大值
min = numArr[i];
}
}
System.out.println("最大的元素为:" + max);
System.out.println("最小的元素为:" + min);
}
}
值传递
值传递和引用传递的区别?
Java官方明确指出 Java中只有值传递
基本数据类型属于'值传递',传递的就是值的副本,值的拷贝,在方法中对参数的修改不会影响原变量
引用数据类型属于'引用传递' 传递的是地址,也就是引用,在方法中对参数的修改会影响原变量
String类型是特殊的引用数据类型 作为参数不会影响原变量 因为String是不可变对象
package com.yuluo;
import java.util.Arrays;
public class ValuePass {
// 值传递和引用传递的区别?
public static void fun(int num){
num++;
}
public static void fun2(int [] nums){
for (int i = 0; i < nums.length; i++) {
nums[i]++;
}
}
public static void main(String[] args) {
int a = 10;
// 调用fun:基本数据类型 参数传递的是值
fun(a);
System.out.println("a = " + a); // 10 修改的是num a的值并没有发生改变
// 调用fun2:引用数据类型 参数传递的值地址
int [] b = {1,2,3,4};
fun2(b);
System.out.println("b = "+ b); // b = [I@4554617c
System.out.println("b的值为"+ Arrays.toString(b)); // b的值为[2, 3, 4, 5]
}
}
二维数组
二维数组:数组中的元素还是数组
二维数组定义:和一维数组定义方式大致相同
二维开辟空间 高维度(第一个中括号)长度必须指定 低维度(第二个中括号)长度可以后续单独指定
package com.yuluo;
public class twoDimeArray {
public static void main(String[] args) {
// 定义一维数组
int [] arr1 = {1,2,3,4,5};
// 定义二维数组
int [][] arr2 = {{1,2,4},{16,17,18}};
// 打印二维数组中内层
System.out.println(arr2[0]); // [I@4554617c
System.out.println(arr2[0][2]); // 4
//
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]); // 全部是内存地址
for (int j = 0; j < arr2[i].length; j++) {
System.out.print(arr2[i][j] + "\t"); // 1 2 4
}
System.out.println();
}
}
}
二维数组的定义案例
package com.atguigu.test3;
/**
* @author WHD
* @description TODO
* @date 2023/8/4 15:38
* 二维数组定义:和一维数组定义方式大致相同
* 二维开辟空间 高维度(第一个中括号)长度必须指定 低维度(第二个中括号)长度可以后续单独指定
*/
public class Test2DArrayDefine {
public static void main(String[] args) {
// 方式1
int [][] arr1;
arr1 = new int[3][4];
// 方式2
// 数组的默认值 二维数组每个元素为一维数组 属于引用数据类型 其默认值为null
// 当我们创建一个长度为2的二维数组 表示在内存中 有两个一维数组 都指向为null
int [][] arr2 = new int[2][];
System.out.println(arr2[0]); // null
System.out.println(arr2[1]); // null
arr2[0] = new int[3];
arr2[0][0] = 11;
arr2[0][1] = 11;
arr2[0][2] = 11;
arr2[1] = new int[2];
arr2[1][0] = 34;
arr2[1][1] = 56;
// 方式3
int [][] arr3 = new int[][]{{1},{22,33,44},{55,55,666}};
// 方式4
int [][] arr4 = {{1},{22,33,44},{55,55,666}};
}
}
杨辉三角案例
package com.yuluo;
/**
* 杨辉三角
* 1
* 1 1
* 1 2 1
* 1 3 3 1
* 1 4 6 4 1
* 1 5 10 10 5 1
*/
public class YangHuiTri {
public static void main(String[] args) {
// 定义一个 6*6 的矩阵
int [][] yh = new int[6][6];
// 遍历 赋值
for (int i = 0; i < yh.length; i++) {
yh[i][0] = 1; // 每一行的第一列为1
yh[i][i] = 1; // 每一行的第i列为1
if(i > 1){ // 表示从第3行开始 赋值有具体的计算
for (int j = 1; j < i; j++) {
yh[i][j] = yh[i-1][j] + yh[i-1][j-1];
}
}
}
// 遍历 打印
for(int i = 0;i < yh.length;i++){
for(int j = 6;j > i;j--){
System.out.print(" "); // 打印一个倒三角形
}
for(int j = 0;j <= i;j++){ // 打印
System.out.print(yh[i][j] + " ");
}
System.out.println();
}
}
}