- 1 数组的概念
- 2 数组的定义
- 3 数组的使用
- 4 数组的遍历
- 5 数组的属性
- 6 数组的默认值
- 7 数组的扩容
- 8 数组的复制
- 9 练习
- 10 面试题
- 11 可变长参数
- 12 数组排序
- 13 Arrays工具类
- 14 数组插入元素
- 15 数组删除元素
- 16 二维数组
概念:一组
连续的存储空间,存储多个相同数据类型的值,长度是固定的。
先声明、再分配空间: 数据类型[] 数组名; 数组名 = new 数据类型[长度];
声明并分配空间: 数据类型[] 数组名 = new 数据类型[长度];
声明并赋值(繁): 数据类型[] 数组名 = new 数据类型[]{value1, value2, value3, ...};
声明并赋值(简): 数据类型[] 数组名 = {value1, value2, value3, ...};
/**
* 数组的定义:四种方式
* 小细节:声明数组的中括号通常写在类型之后 数组名之前 也可以写在 数组名之后
*/
public class TestArrayDefine {
public static void main(String args []) {
// 方式1 先声明 再开辟空间
int [] arr1;
arr1 = new int[3];
// 方式2 声明并且开辟空间
int [] arr2 = new int[5];
// 方式3 声明并且赋值 (繁琐)
int [] arr3 = new int[]{1,3,5,8,9,6,55,22};
// 方式4 声明并且赋值 简单
int [] arr4 = {89,55,666,999,120,352};
}
}数组的元素:数组中的每个数据称之为数组中的元素
数组的访问:对数组中的元素赋值以及取值的操作 统称为数组的访问
下标、索引、角标、index : 下标自动生成 从0开始 往后依次+1
访问数组通过下标访问:
赋值 数组名[下标] = 值;
取值 System.out.println(数组名[下标]);
访问不存在的下标 将会导致数组下标越界异常 ArrayIndexOutOfBoundsException
/**
* ctrl + d 赋值当前行
*/
public class TestArrayUse {
public static void main(String[] args) {
int [] arr1 = new int[5];
// 赋值
arr1[0] = 11;
arr1[1] = 132;
arr1[2] = 321;
arr1[3] = 444;
arr1[4] = 666;
// arr1[213231] = 888;
// 取值
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(arr1[2]);
System.out.println(arr1[3]);
System.out.println(arr1[4]);
// System.out.println(arr1[5]);
}
}数组的遍历:逐一对数组中的元素进行访问 称之为数组的遍历
public class TestArrayForeach {
public static void main(String[] args) {
int [] nums = new int[5];
// 使用for循环给数组元素赋值
Scanner input = new Scanner(System.in);
for(int i = 0;i < 5;i++){
System.out.println("请输入第" + (i + 1) + "个元素的值");
nums[i] = input.nextInt();
}
System.out.println("---------------------------------------------------");
// 使用for循环获取数组的元素
for(int i = 0; i < 5; i++){
System.out.println("第" + (i + 1) + "个元素的值为" + nums[i]);
}
System.out.println("程序结束");
}
}数组的属性:length属性 表示数组的长度 是一个int类型的整数 可以通过数组名.length获取
public class TestArrayField {
public static void main(String[] args) {
int [] arr1 = {454, 8, 2, 655, 54};
System.out.println(arr1.length);
for(int i = 0; i < arr1.length; i++){
System.out.println(arr1[i]);
}
}
}数组的默认值:数组作为引用数据类型 其元素是有默认值的 当我们给数组开辟空间以后 默认值即存在
整数:0
浮点:0.0
字符:\u0000
布尔:false
其他:null (空)
JDK提供了一个用于操作数组的工具类 java.util.Arrays
此类中提供大量的用于操作数组的各种方法
Arrays.toString(数组名) : 将数组中的元素转换为字符串 返回
public class TestArrayDefaultValue {
public static void main(String[] args) {
byte [] arr1 = new byte[3];
String str = Arrays.toString(arr1);
System.out.println("str = " + str);
short [] arr2 = new short[4];
System.out.println(Arrays.toString(arr2));
int [] arr3 = new int[5];
System.out.println(Arrays.toString(arr3));
long [] arr4 = new long[6];
System.out.println(Arrays.toString(arr4));
System.out.println("----------------------------------------------");
float [] arr5 = new float[3];
System.out.println(Arrays.toString(arr5));
double [] arr6 = new double[4];
System.out.println(Arrays.toString(arr6));
System.out.println("----------------------------------------------");
boolean [] arr7 = new boolean[5];
System.out.println(Arrays.toString(arr7));
System.out.println("----------------------------------------------");
char [] arr8 = new char[4];
System.out.println(Arrays.toString(arr8));
System.out.println("----------------------------------------------");
// 关于null值 以及 空指针异常 NullPointerException
// 使用一个为null的对象 调用任何的属性 或者 方法 都将出现空指针异常
String [] arr9 = new String[2];
System.out.println(Arrays.toString(arr9));
}
}数组的扩容:
实现步骤:
- 1.创建比原数组更长的新数组-
- 2.将原数组中的元素依次复制到新数组中-
- 3.将新数组的地址赋值给原数组
数组作为引用数据类型 其数组名中保存的是指向堆中的地址 所以 当我们把一个数组 赋值 给 另外一个数组
赋值的是地址
public class TestArrayGrow {
public static void main(String[] args) {
int [] oldArr = {1,2,3,4,5};
int [] newArr = new int[oldArr.length * 2];
for(int i = 0; i < oldArr.length; i++){
newArr[i] = oldArr[i];
}
System.out.println(Arrays.toString(newArr));
// 数组作为引用数据类型 其数组名中保存的是指向堆中的地址
// 所以 当我们把一个数组 赋值 给 另外一个数组
// 赋值的是地址
System.out.println(oldArr);
System.out.println(newArr);
oldArr = newArr;
System.out.println("==================地址赋值以后===================");
System.out.println(oldArr);
System.out.println(newArr);
System.out.println(oldArr.length);
System.out.println(Arrays.toString(oldArr));
System.out.println("------------------------------------------------------------------");
newArr[9] = 666;
System.out.println(oldArr[9]); // 0? 666?
}
}复制数组的三种方式:
- 循环将原数组中所有元素逐一赋值给新数组。
- System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);
- java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。
public class TestArrayCopy {
public static void main(String[] args) {
int [] oldArr = {1,2,3,4,5};
int [] newArr = new int[10];
System.arraycopy(oldArr, 1, newArr, 2, 2);
System.out.println(Arrays.toString(newArr));
System.out.println("-------------------------------------------------");
int [] nums = {11,22,33,44,55};
// 第一个参数 原数组
// 第二个参数 新长度 新长度可以小于等于或者大于原数组的长度
int [] newNums = Arrays.copyOf(nums, 5);
System.out.println(Arrays.toString(newNums));
}
}/**
* 数组练习1: 统计int类型数组中所有元素的总和,平均值。
*/
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];
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);
}
}/**
* 数组练习2:求一个数组中的最大值,或者最小值。
* 分析:先假设一个最大值/最小值 依次与其他元素进行比较 如果遇到更大的/更小的 就交换
* 头衔
*/
public class TestArrayExercise2 {
public static void main(String[] args) {
int [] nums = {562,999,458,896,36985,210,254,785,3,6,5,2};
int max = nums[0]; // 假设第一个元素为最大元素
int min = nums[0]; // 假设第一个元素为最小元素
// 逐一跟后续的元素进行比较
// 因为我们假设的元素下标为0 所以比较元素下标从1 开始 因为 不需要自己跟自己比了
for(int i = 1; i < nums.length; i++){
if(max < nums[i]){ // 如果遇到了更大的元素 则交换'最大元素' 头衔
max = nums[i]; // 交换
}
if(min > nums[i]){// 如果遇到了更小的元素 则交换'最小元素' 头衔
min = nums[i]; // 交换
}
}
System.out.println("最大的元素为:" + max);
System.out.println("最小的元素为:" + min);
}
}值传递和引用传递的区别?
Java官方明确指出 Java中只有值传递
基本数据类型属于'值传递',传递的就是值的副本,值的拷贝,在方法中对参数的修改不会影响原变量
引用数据类型属于'引用传递' 传递的是地址,也就是引用,在方法中对参数的修改会影响原变量
String类型是特殊的引用数据类型 作为参数不会影响原变量 因为String是不可变
public class TestArrayInterView {
public static void m1(int num){
num++;
}
public static void m2(int [] nums){
System.out.println("nums = " + nums);
for (int i = 0; i < nums.length; i++) {
nums[i]++;
}
}
public static void main(String[] args) {
int a = 10;
m1(a);
System.out.println("a = " + a); // 10
int [] b = {1,2,3,4,5};
m2(b);
System.out.println("b = " + b);
System.out.println(Arrays.toString(b)); // 2,3,4,5,6
}
}可变长参数:可接收多个同类型实参,个数不限,使用方式与数组相同。
要求:
- 1.整个形参列表中只能有一个可变长参数
- 2.必须书写在形参列表的末尾
格式:数据类型...参数名
public class TestChangedParam {
public static void m1(int ... args){
System.out.println("m1方法开始执行");
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
System.out.println("m1方法执行完毕");
}
public static void m2(int [] args){
System.out.println("m2方法开始执行");
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
System.out.println("m2方法执行完毕");
}
public static void main(String[] args) {
m1(1, 2, 3, 4, 5, 6);
int [] nums = new int[4];
m2(nums);
}
}/**
* 冒泡排序:相邻的两个元素比较大小 条件成立 则交换位置 直到数列排列正确
*
* 比较的轮数为:n - 1
* 每一轮比较的次数:n - 1 - ?
*
* 外层循环控制比较的轮数:n - 1
* 内存循环控制每一轮比较的次数:n - 1 - i
*/
public class TestBubbleSort {
public static void main(String[] args) {
int [] nums = {562, 451, 110, 23, 45, 85, 96, 666};
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]){
// 交换元素写法固定规律:上一行的等号右边的值 在下一行 直接写在等号左边 等待被覆盖
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));
}
}/**
* 选择排序:固定位置的元素与其他元素依次比较大小,遇到需要交换位置的元素,先不交换,
* 使用应该被交换位置的元素继续往后比较,等待一轮比较完成,统一交换一次位置。
*
* 选择排序比较的轮数依然为: n - 1
* 每一轮比较的次数:最多的一次为n - 1 后续每一轮递减1
*
* 分析:
* 将外层循环作为比较的元素A 从第一个元素开始 到倒数第二个元素
* 将内层循环作为比较的元素B 从第二个元素开始 到最后一个元素 (即每一轮都是从比较的元素A 紧邻的后边的位置开始)
*
* 选择排序每一轮最多只会交换一次位置 所以即使每一轮都交换位置 也最多交换长度-1次 因为轮数为长度-1轮
*/
public class TestChoiceSort {
public static void main(String[] args) {
int [] nums = {-2, 562, -1, 451, 110, 23, 45, 85, 96, 666};
int count = 0;
for(int i = 0; i < nums.length -1; i++){ // A
int moveIndex = i; // 定义moveIndex 表示为需要最终交换位置的下标
for(int j = i + 1; j < nums.length; j++){ // B
if(nums[moveIndex] < nums[j]){
moveIndex = j;
}
}
// 如果moveIndex 和 i的值不相同 则表示需要交换元素
// 因为 只有比较大小的条件成立 moveIndex的值 才会发生变化
// 而条件成立 则表示有需要交换位置的元素
// 最终将moveIndex 和 i 对应位置的元素进行交换 因为
// i 表示每一轮的第一个元素 而moveIndex最终将停留在最大/最小的元素
if (moveIndex != i){
int temp = nums[i];
nums[i] = nums[moveIndex];
nums[moveIndex] = temp;
count++;
}
}
System.out.println(Arrays.toString(nums));
System.out.println("一共交换了" + count + "次位置");
}
}java.util.Arrays 是JDK提供的一个用于操作数组的工具类
toString(数组名) : 将数组中的元素转换为字符串
copyOf(数组名,新长度) : 复制数组
sort(数组名) : 将数组按照升序排序 属于快速排序 实现原理为 递归
fill(数组名,填充元素) : 将数组按照指定元素进行填充
binarySearch(数组名,元素) : 使用二分查找法查找某个元素在数组中的下标
public class TestArrays {
public static void main(String[] args) {
int [] nums = {56,12,22,41,85,99};
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
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));
System.out.println("--------------------------------------------");
Arrays.fill(newArr, 666);
System.out.println(Arrays.toString(newArr));
System.out.println("--------------------------------------------");
int index = Arrays.binarySearch(nums, 999);
System.out.println("index = " + index);
}
}编写方法实现在数组中插入元素
扩展:可以使用System.arraycopy方法 实现插入效果
public class TestArrayInsert {
public static void main(String[] args) {
int [] nums = {1, 2, 3, 4, 5};
int[] newArray = insert(nums, -8, 666);
System.out.println(Arrays.toString(newArray));
}
/**
*
* @param oldArray 操作的数据
* @param index 插入元素的位置
* @param num 插入的元素
* @return 新的数组
*/
public static int[] insert(int [] oldArray,int index,int num){
// 下标不能小于0 或者 不能大于数组的长度
if(index < 0 || index > oldArray.length){
System.out.println("下标不合法");
// 如果下标不合法 则将传入的数组 直接返回 表示没有做任何操作
return oldArray;
}
// 代码执行到这里 表示下标没问题
// 准备一个长度+1的数组 用于插入元素
int [] newArray = new int[oldArray.length + 1];
// 遍历开始移动元素
for(int i = 0; i < oldArray.length; i++){
// 情况1 小于插入下标 则直接复制到新数组中
if (i < index) {
newArray[i] = oldArray[i];
} else { // 情况2 大于或者等于插入下标 则移动到新数组的+1位置
newArray[i + 1] = oldArray[i];
}
}
// 空缺位插入指定的元素
newArray[index] = num;
return newArray; // 将新数组返回
}
}编写方法实现删除数组中的元素
扩展:可以使用System.arraycopy方法 实现删除效果
public class TestArrayDelete {
public static int[] delete(int [] oldArray,int index){
// 判断下标 如果小于0 或者 大于等于数组长度 表示不合法 因为删除 只能删除有效范围以内的
if(index < 0 || index >= oldArray.length){
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; // 将新数组返回
}
public static void main(String[] args) {
int [] nums = {1,2,3,4,5};
int[] delete = delete(nums, -5);
System.out.println(Arrays.toString(delete));
}
}二维数组:数组中的元素还是数组
public class Test2DArray {
public static void main(String[] args) {
int [] arr1 = {1,2,3,4,5};
int [] [] arr2 = { {1,2,4} , {55,88,66} , {666} , {999,888,777}};
System.out.println(arr2[0]);
System.out.println(arr2[0][0]);
System.out.println(arr2[0][1]);
System.out.println(arr2[0][2]);
System.out.println("----------------------------------");
System.out.println(arr2[1][0]);
System.out.println(arr2[1][1]);
System.out.println(arr2[1][2]);
System.out.println("----------------------------------");
System.out.println(arr2[2][0]);
System.out.println("----------------------------------");
System.out.println(arr2[3][0]);
System.out.println(arr2[3][1]);
System.out.println(arr2[3][2]);
System.out.println("----------------------------------");
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");
}
System.out.println();
}
}
}二维数组定义:和一维数组定义方式大致相同
二维开辟空间 高维度(第一个中括号)长度必须指定 低维度(第二个中括号)长度可以后续单独指定
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]);
System.out.println(arr2[1]);
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.atguigu.test3;
/**
* 杨辉三角
* 1
* 1 1
* 1 2 1
* 1 3 3 1
* 1 4 6 4 1
* 1 5 10 10 5 1
*/
public class TestYangHuiTriangle {
public static void main(String[] args) {
int [][] yh = new int[6][6];
for(int i = 0; i < yh.length; i++){
yh[i][0] = 1; // 每一行的第一列为1
yh[i][i] = 1;
if (i > 1) { // 表示从第3行开始 赋值有具体的计算
for(int j = 1; j < i; j++){ // 因为每一行的第一列 和 最后一列都有值了 为0 所以 我们只需要赋值中间的元素
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();
}
}
}