![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8a1071c4512ff5e5e551f102fd05acd9.png)
一、数组的基本概念
1.1 什么是数组?
数组是存放相同数据类型的集合,在内存中是一段连续的内存空间
1.2 数组的创建和初始化
1.2.1 创建
public static void main(String[] args) {
//1.中括号里面不能有数字
int[] array1 = {1,2,3,4,5};//最常用
//2.中括号里面不能有数字
int[] array2 = new int[]{1,2,3,4,5};//跟第一种一样,写法更复杂
//3.不确定数组具体元素
int[] array3 = new int[10];//未初始化,里面默认为0
array3[0] = 1;//初始化要这样
}
public static void main(String[] args) {
double[] array = new double[10];//每个元素都是0
String[] array2 = new String[10];//Java里面支持字符串数组,他的每个值初始化都是null
boolean[] array3 = new Boolean[10];//默认都是false
}
1.2.2 初始化
1.2.2.1 动态初始化
未指定元素具体值
int[] array = new int[10];//未指定元素具体
1.2.2.2 静态初始化
定义的同时并初始化
int[] array = new int[]{0,1,2,3};//定义的同时并初始化
1.2.2.3 注意事项
-
静态初始化虽然没有指定数组的长度,编译器在编译时会根据
{}
中元素个数来确定数组的长度。 -
静态初始化时,
{}
中数据类型必须与[]
前数据类型一致。 -
静态初始化可以简写,省去后面的
new 类型[]
。但是编译的时候,还是会还原回来的 -
其实数组创建也可以用
C
语言的形式int array[10] = {1,2,3};
-
不确定数组具体内容,使用动态初始化(即创建方法3)
-
初始化也可以分成两行写
int[] array1; array = new int[10]; int[] array2; array2 = new int[]{1,2,3}; //这种写法不能省略new int[],否则会编译失败
另外,不简写的话,可以重复定义多次
int[] array1; array1 = new int[]{1,2,3}; array1 = new int[]{11,22,33};
1.3 数组的使用
1.3.1 数组中元素的访问
数组在内存中是一段连续的空间,下标是从0开始的,数组可以通过下标来访问任意位置的元素
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
//1.既可以通过下标访问元素
System.out.println(array[3]);//访问下标为3,实际上值为4的元素
//2.又可以通过下标修改元素
array[4] = 55;//下标为4,实际上值为5的元素被修改成了55
System.out.println(array[4]);
}
要注意,不要越界
public static void main(String[] args) {
int[] array = {1,2,3,4,5};//数组长度为5,最大下标为4
System.out.println(array[99]);//严重越界!!!
}
1.3.2 遍历数组
两种方式
-
for
循环:快捷键for+i
-
for-each
循环:加强版的for
循环public static void main(String[] args) { int[] array = {1,2,3,4,5}; //在数组中,我们可以通过 数组对象.length 来获取数组长度 //方式1:for循环遍历 for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } //方式2:for-each循环 //不仅可以打印数组,还可以打印集合当中的元素 //而且不需要用到下标 for (int x : array) { System.out.print(x + " ");//其实就是把数组元素对应的值赋给x,然后打印x } System.out.println(); }
我们还可以通过Java
官方提供的工具打印数组
public static void main(String[] args) {
//Arrays:工具类->帮助我们操作数组,他的返回值是String
String ret = Arrays.toString(array);
System.out.println(ret);
//直接可以写成一句
//System.out.println(Arrays.toString(array));
}
二、数组是引用类型
2.1 初识JVM的内存分布
首先,我们先了解一下:引用
引用是一个变量,里面存储的是地址
int[] array = {1,2,3,4};//array1这个引用,引用了(指向了) {1,2,3,4}这个对象
//引用和指向代表的是一个意思
那么,我们再来看一下初识JVM
的内存分布
Java
虚拟机栈:我们常说的栈(局部变量…)
Java
本地⽅法栈:运⾏⼀些由C/C++
代码编写的程序【JVM
其实是⼀个软件,是⼀个由C/C++
代码编写的软件】堆:只要是对象,都在堆上分配内存(数组…)
程序计数器:存放⼀些指令
方法区:静态的成员变量…
划分内存的好处:方便管理
我们来看这段代码
public static void main(String[] args) {
int[] array = {1,2,3};
System.out.println(array);//[I@1b6d3586
}
2.2 基本类型变量与引用类型变量
基础类型变量,存放的是数值
引用类型变量,存放的是地址
1.当两个数组指向同一块内存空间时
public static void main(String[] args) {
int[] array1 = {1,2,3,4};
int[] array2 = array1;//array2 引用了 array1 引用的对象(不是引用指向引用)
System.out.println("array1" + Arrays.toString(array1));
System.out.println("array2" + Arrays.toString(array2));
System.out.println("-------------------");
array2[0] = 100;
System.out.println("array1" + Arrays.toString(array1));
System.out.println("array2" + Arrays.toString(array2));
}
2.数组内容相同,不代表他们俩就一模一样
public static void main(String[] args) {
int[] array1 = {1,2,3,4};
int[] array2 = {1,2,3,4};
System.out.println(array1);
System.out.println(array2);//两个数组地址不同
}
//备注:new出来的就是新的
2.3 再谈引用变量
public static void main(String[] args) {
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;
System.out.println(Arrays.toString(array2));
}
2.4 关于null
null
代表不指向任何对象
当数组被赋值为null
的时候,针对他的操作,都会造成空指针异常
public static void main(String[] args) {
int[] array = null;//引用类型赋值为null->代表array这个引用不指向任何对象,这时候对他进行操作,就会空指针异常
array[0] = 1;
System.out.println(array.length);
}
注意:在Java
中,并没有约定null
跟0号地址的内存有关联
小结:
-
引用能指向引用吗?
不能!引用只能指向对象
array1 = array2;//代表array1这个引用 引用了(指向了)array2所引用的对象
-
⼀个引用能同时指向多个对象吗?
不能同时.一个引用只能同时指向一个对象
-
引用一定在栈上吗?(就是我们画的两个框框,左边的那个)
不是的.现在之所以把它画在栈上,是因为我们目前只是接触到局部变量,还没有接触成员变量,后面会接触到
public class Main { public int[] array = {1,2,3,4,5,6,7,8};//成员变量->在堆上 public static void main7(String[] args) { int[] array1 = {1,2,3,4};//局部变量->在栈上 array1 = new int[]{11,12,13,14}; array1 = new int[]{6,7,8,9}; }
-
引用赋值为
null
代表啥?int[] array = null;//代表这个引用 不指向任何对象
三、数组的使用
3.1 保存数据
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
3.2 作为函数的参数
3.2.1 参数为基本数据类型
我们之前在方法的时候讲过,形参的改变不会影响实参
public class TestDemo2 {
public static void func(int a) {
a = 20;
}
public static void main(String[] args) {
int x = 10;
func(x);
System.out.println(x);
}
}
那么传过去的数据是数组类型也是这样
3.2.2 参数为引用数据类型
public static void func(int[] arr) {
arr = new int[]{11,22,33,44};
}
public static void main(String[] args) {
int[] array1 = {1,2,3,4};
func(array1);
System.out.println(Arrays.toString(array1));
}
public static void func(int[] arr) {
arr[0] = 100;
}
public static void main(String[] args) {
int[] array1 = {1,2,3,4};
func(array1);
System.out.println(Arrays.toString(array1));
}
上面这两种方式,虽然都是传了地址,但是他们干的事不太一样
3.3 作为函数的返回值
public static int[] func5() {
int[] array = {1,2,3,4};
return array;
}
public static void main11(String[] args) {
int[] ret = func5();//返回的是数组,用数组接收
System.out.println(Arrays.toString(ret));
}
四、数组的相关练习
4.1 数组转字符串
写⼀个函数将 数组以字符串的形式进行输出 [1, 2, 3, 4]
public class TestDemo1 {
public static String myToString(int[] array) {
String ret = "[";
for (int i = 0; i < array.length; i++) {
ret += array[i];
if(i != array.length - 1) {
ret += ",";
}
}
ret += "]";
return ret;
}
public static void main(String[] args) {
int[] array = {1,2,3,4};
String ret = myToString(array);
System.out.println(ret);
}
}
当然,我们还可以调用Arrays
下面的toString
public static void main(String[] args) {
//Arrays:工具类->帮助我们操作数组,他的返回值是String
String ret = Arrays.toString(array);
System.out.println(ret);
//直接可以写成一句
//System.out.println(Arrays.toString(array));
}
4.2 数组的拷贝
数组拷贝
方法一:使⽤for循环进行拷贝
public static void main13(String[] args) {
int[] array = {1,2,3,4};
int[] copy = new int[array.length];
for (int i = 0; i < array.length; i++) {
copy[i] = array[i];
}
System.out.println(Arrays.toString(copy));
}
方法二:Arrays.copyOf
(你要拷贝的数组,新的长度)
public static void main14(String[] args) {
int[] array = {1,2,3,4};
//虽然是发⽣了拷贝 也可以看做是 扩容
int[] copy = Arrays.copyOf(array,array.length);
int[] ret = Arrays.copyOfRange(array,1,3);//这种方法需要接收返回值
System.out.println(Arrays.toString(copy));//[1,2,3,4]
System.out.println(Arrays.toString(ret));//[2,3]
}
方法三:System.arraycopy
你要拷贝的数组,开始拷贝的下标,目的地数组,目的地数组的位置,你要拷贝的长度
public static void main15(String[] args) {
int[] array = {1,2,3,4};
int[] copy = new int[array.length];
System.arraycopy(array,0,copy,0,array.length);
System.out.println(Arrays.toString(copy));
}
方法四:array.clone()
产生了一个新的副本
public static void main(String[] args) {
int[] array = {1,2,3,4};
int[] copy = array.clone();
System.out.println(Arrays.toString(copy));
System.out.println(array);
System.out.println(copy);
}
4.3 求数组中元素的平均值
public static double avg(int[] array) {
int sum = 0;
for (int i = 0; i < array.length; i++) {
sum = sum + array[i];
}
return sum*1.0 / array.length;
}
4.4 顺序查找
public static int search(int[] array,int key) {
for (int i = 0; i < array.length; i++) {
if(array[i] == key) {
return i;
}
}
//如果代码走到这里,要不是没进去for循环,要不就是没找到
return -1;//返回-1->因为数组没有负数下标
}