数组的基本概念
数组创建
T[] 数组名 = new T[N];T:数组中存放元素的数据类型
T \[\] :代表数组本身的类型
N:数组的长度(数组能存放多少个元素)
2.
int[] arr1=new int[10]; double[] array2=new double[10]; String[] array3=new String[20];数组两种初始化方式
动态初始化
创建数组时,只指定数组长度,不写元素值,元素自动赋默认值
只规定数组大小,里面元素是对应类型的默认值
//静态初始化 int[] array1=new int[10];静态初始化
创建数组时,直接写出数组里面的元素,编译器自动根据大括号里元素个数算出数组长度
//动态初始化 int[] array2=new int[]{1,2,3,4,5,6,7,8,9}; double[] array3=new double[]{1.0,2.0,3.0,4.0}; String[] array4=new String[]{"tom","Lily","java"};数组元素默认值
当数组只开辟空间,没有手动赋值时,元素自带默认值:
引用类型(String、类对象等)默认值:null
String[] words = new String[3]; // 三个元素默认都是null
重点注意事项静态初始化不用手动写长度,编译器自动数
{}里元素个数。
{}里的数据类型必须和数组定义的类型一致。简写格式
{...}不能拆分成两行定义
int[] array5; array5=new int[]{1,3,5,3,6,7}; //这样是可行的 int[] array6; array6={1,2,34,54,65};//编译报错,简写只能在定义数组那一行初始化 int[] array7={1,2,3,4,5,6}; //在定数组这一行初始化,是可行的
数组的基本使用
数组中元素访问
- 数组在内存是连续空间,下标从 0 开始递增,通过数组下标访问元素
int[] array1=new int[]{10,20,30,40,50}; System.out.println(array1[0]); System.out.println(array1[2]); System.out.println(array1[3]); // 修噶下标为0 的元素、 array1[0]=1; System.out.println(array1[0]);
- 注意事项
连续内存 → 支持随机访问,直接用下标快速读取任意位置元素。
下标范围:[0, 数组长度),不能越界。
数组有N个元素,下标最大是N-1
下标越界抛出异常遍历数组
遍历:把数组里所有元素全部访问一遍
方式 1: for 循环(能拿到数组下标)
利用 数组名.length 获取数组长度
int[] array1=new int[]{1,2,3,4,5,6}; for(int i=0;i<array1.length;i++) { System.out.printf("%d ",array1[i]); } System.out.println();方式 2:for-each 增强 for 循环(只读取元素,拿不到下标)
语法: for(元素类型 变量 : 数组名)
特点: 不用写循环条件,简化遍历
无法获取当前元素下标
//for-each 增强for循环 int[] array2=new int[]{1,3,4,5,6}; for(int x:array2) { System.out.printf("%d ",x); } System.out.println();数组是引用类型
基本类型变量与引用类型变量的区别
基本类型变量 :栈里面直接存值本身
引用类型变量:栈里面存对象在堆中的地址,对象本体放在堆里
3. 基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值
引用数据类型创建的变量,⼀般称为对象的引用,其空间中存储的是对象所在空间的地址
4. 引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始
地址, 通过该地址,引用变量便可以去操作对象Java 的引用类似 C 语言指针,但 Java 不能手动对地址做加减运算,安全性更高
public static void func1() { int[] array1=new int[3]; array1[0]=10; array1[1]=20; array1[2]=30; int[] array2=new int[]{1,2,3,4,5}; array2[0]=100; array2[1]=200; // 变量里存的不是变量本身,而是在堆内存的地址 array1=array2; //两个变量共用同一块内存地址 array1[2]=300; array1[3]=400; array1[4]=500; for(int i=0;i<array2.length;i++) { System.out.println(array2[i]); } }
- 关键总结
Java 数组属于引用类型:
a)变量里存的不是数组本身,而是数组在堆内存的地址;
b)array1 = array2 只是拷贝地址,两个变量共用同一个数组对象;
c)无论用哪个引用修改数组内部元素,都会互相影响NULL
什么是 null
a)null 在 Java 中表示空引用 ,是一个不指向任何对象的引用
b)Java 里引用类型(数组、类、String 等)的变量,可以赋值为 null,代表这个引用 变量没有指向堆里的任何对象
c)基本数据类型(int / double / boolean)不能赋值为 null,只有引用类型可以和 C 语言 NULL 的区别
相似点 :都代表无效的内存位置,不能读写
重要区别 :Java 的 null 不等价于内存 0 号地址,只是 Java 层面的 "空标记",和 C 语言空指针底层含义不一样空指针什么时候会出现
只要用一个值为null的引用,去调用属性 / 方法 / 访问数组元素,就会触发 NPE
总结
int[] arr1=null; int[] arr2=new int[]{1,2,3,4,5,6,7}; System.out.println(arr1[0]); // System.out.println(arr2[0]);a)arr1:只是一个空引用,不存在数组,arr10 空指针
b)arr2:数组对象存在,可以访问元素,arr20 是 1
数组的应用场景
保存数据
- 知识点
a)数组:用来批量保存多个同类型数据
b)数组下标从 0 开始,最大下标 = 数组长度 -1
c)数组名.length:获取数组元素个数
d)for 循环:适合知道循环次数的遍历场景
int[] array={1,2,3}; for(int i=0;i<array.length;i++) { System.out.println(array[i]+" "); }
参数传递(值传递)
Java 中只有值传递,没有引用传递
基本类型和引用类型,本质都是拷贝一份 "值" 传给方法
基本数据类型作为参数
public static void main(String[] args) { int num = 0; func(num); System.out.println("num = " + num); } public static void func(int x) { x = 10; System.out.println("x = " + x); }
2. 斐波那契数列
//方法:返回int[]数组,存放婓波那些前n项 public static int[]fib(int n) { if(n<=0) { return null; } int[] array=new int[n]; array[0]=array[1]=1; //当前项等于前两项之和 for(int i=2;i<n;i++) { array[i]=array[i-1]+array[i-2]; } return array; }
Arrays 工具类 和 数组知识点
Java 数组常用操作,包含Arrays工具类、数组拷贝、查找、排序、逆序
数组转字符串 Arrays.toString()
- 作用:快速把数组转为字符串格式打印,不用自己循环拼接
int[] arr=new int[]{1,2,3,4,5,6,7}; String newArr= Arrays.toString(arr); System.out.println(newArr);
- 注意:直接打印数组对象名,输出的是地址哈希值,不是数组内容
数组拷贝
直接赋值(浅引用,不是拷贝)
int[] arr=new int[]{1,2,3,4,5}; int[] newArr=arr; //newArr 和 arr 指向的是同一块数组 newArr[0]=100; System.out.println(Arrays.toString(arr)); // newArr 的修改 会导致 arr 也被修改Arrays.copyOf / Arrays.copyOfRange(真正拷贝,生成新数组)
//Arrays.copyOf/Arrays.copyOfRange 是拷贝 int[] arr=new int[]{1,2,3,4,5,6,7}; //copyOf(原数组,新数组长度) int[] newArr=Arrays.copyOf(arr,arr.length); arr[0]=10; System.out.println("arr: "+Arrays.toString(arr)); System.out.println("newArr: "+Arrays.toString(newArr)); //不受arr 的影响 //copyOfRange (原数组,起始下标,结束下标) //左闭,右开 int[] newArr2=Arrays.copyOfRange(arr,1,5); System.out.println("newArr2: "+Arrays.toString(newArr2));区分 :
基本类型数组拷贝没问题;
引用类型数组拷贝是浅拷贝自己手写数组拷贝
public static int[] copyOf(int[] arr) { int[] ret=new int[arr.length]; for(int i=0;i<arr.length;i++) { ret[i]=arr[i]; } return ret; }功能:
手写版数组拷贝,深拷贝(对于 int 基本类型数组),复制完成后,修改原数组arr不会影响新数组ret,修改ret也不会影响arr
顺序查找(线性查找)
从头到尾逐个比对元素,找到返回下标,找不到返回 -1
//顺序查找,找到返回下标,找不到返回-1 public static int find(int[] arr,int data) { for(int i=0;i<arr.length;i++) { if(arr[i]==data) { return i; } } return -1; }
- 缺点:
数据量大的时候效率低
不需要数组有序
二分查找(折半查找)
思路:取中间元素,比较目标值,缩小查找区间
//二分查找 public static int binarySearch(int[] arr,int toFind) { int left=0; int right=arr.length-1; while(left<=right) { int mid=(left+right+1)/2; if(toFind<arr[mid]) { right=mid-1; } else if (toFind>arr[mid]) { left=mid+1; } else { return mid;// 找到 } } return -1; //没找到返回 -1 }
优点:数据越多,效率优势越大
Java 自带Arrays.binarySearch()方法
int ret2=Arrays.binarySearch(arr,6); System.out.println(ret2);数组排序:冒泡排序
升序思路:相邻两个元素比较,前大后小就交换;
每一轮把最大元素 "冒泡" 到末尾
降序思路:相邻两个元素比较,前小后大就交换;
每一轮把最小元素 "冒泡" 到末尾
public static void bubbleSort(int[] arr) { //外层控制轮数 //内层比较,每轮末尾 i 个已经排好的不用比较 for(int i=0;i<arr.length;i++) { for(int j=0;j<arr.length-i-1;j++) { //如果前面的比后面的数据大,就交换 if(arr[j]>arr[j+1]) //要改成降序的话,把大于改成小于就行 { int temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } }
- Java 内置:Arrays.sort(arr),底层是优化后的排序,性能远高于手写冒泡
数组逆序
思路:双指针,left 指向头部,right 指向尾部,交换两个元素,left++,right--,直到 left >= right
// 数组逆序 双指针 先交换元素,在变化指针 public static void reverse(int[] arr) { int left=0; int right=arr.length-1; while(left<right) { int tmp=arr[left]; arr[left]=arr[right]; arr[right]=tmp; left++; right--; } }
二维数组
普通二维数组
二维数组本质:是一维数组,数组里每一个元素又是一个一维数组
语法格式
数据类型[][] 数组名称 = new 数据类型 [行数][列数] {初始化数据};特点:行不能省略,列可以省略
// 二维数组 public static void main(String[] args) { int[][] a={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }; //a.length 是行数 for(int row=0;row<a.length;row++) { //a[row].length 是列数 for(int col=0;col<a[row].length;col++) { System.out.printf("%d\t",a[row][col]); } //换行 System.out.println(); } }a.length:二维数组行数
arow.length:第row行一维数组的长度(当前行的列数)
不规则二维数组
- 定义时只确定行数,每一行的列数不固定,各行长度不一样
int[][] array = new int[2][]; // 定义2行,列暂时不指定 array[0] = new int[3]; // 第0行,3个元素(3列) array[1] = new int[5]; // 第1行,5个元素(5列)
- 第 0 行:3 列
第 1 行:5 列
内存理解:外层数组保存两个一维数组的地址,两个一维数组长度不同










