说明
这是一个完善了但又不完善的笔记,或许以后会更新
可以参考但请务必超越
源文件
Tools
数组的定义与使用
- 啥是数组?
- 定义是啥?
- 数组咋用?
咸鱼三连。
1.数组的基本用法
1.1 什么是数组
数组:存储一组相同数据类型的数组的集合
数组本质上就是让我们能 "批量" 创建相同类型的变量。
我们要表示2个数组的时候可以直接创建2个变量
int a = 0;
int b = 0;
那要是一万个,那也太多了,这时候就可以使用数组。
注意:在Java中,数组中包含的变量必须是相同类型
1.2 创建数组
类型[] 数组变量名 = {初始化值};
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
注意:和C语言不一样,不可以在中括号中输入数据
这样写是直接初始化了内容,内容就是1234567890
还有其他的创建方式
int[] array = new int[3];
这里使用了一个关键字new
:实例化一个对象。
意味着:Java当中的数组,也是一个对象,第一种写法虽然没写,但也是一个对象,只不过省略了new int[]
而且这样的创建方式是没有初始化的,只是开辟了空间
所以不省略的写法就是
int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
注意还是不要在[]
里写数字
int arr[]
其实数组也可以这么写,这样就和C语言更相似了
在C语言中使用int arr[]
,其实arr
只是数组的变量,他的类型还是int[]
,在C中调试的时候也是显示int[]
等于多少多少
说到底数组还是int[]
,只不过在Java中把他改的更顺了一些,int
和[]
是一体的所以放在了一起
虽然可能少数人感觉看的不舒服,实际上C语言才写的不太对...
1.3 数组的使用
获取长度
使用array.length
System.out.println(array.length);
数组的长度不需要像C语言那样再去求了,站在巨人的肩膀上自然就会优化的更好,补足一些缺陷
注意在for循环中不能写=array.length
,否则会数组越界
访问元素
数组,是有下标来排列顺序的。从0下标开始,使用的时候使用下标即可
System.out.println(array[5]);
修改数组元素就使用下标改
arr[5] = 10;
数组越界
如果我们访问的时候访问一个-1
下标或者其他数组范围外的下标,Java就会直接报错,如果是C语言可能只是个警告或者运行顺利就过去了
这里就提现了Java的安全性,也很严谨
站在巨人的肩膀上
和上面的获取数组长度一样,老大哥C语言确实是有一些问题的,不过也没必要改,经典就是经典。所以有本书叫《C陷阱与缺陷》,没见其他语言的缺陷。这很正常,你觉得他有问题,那你使用他你就得适应,或者开发新语言,优化语言,弥补缺陷,这非常好。
idea 增强for循环
idea提供了一个foreach
的快捷输入方式,叫做增强for循环
for (int x : array) {
System.out.print(x + " ");
}
区别
- for循环是可以拿到下标的
- for each是拿不到下标的
假如在数组中找到一个元素返回他的下标,就是用for,如果只是要找到这个元素返回元素,使用for each就可以了。到后面集合中使用的更多一点
在不同的情况下都各有好处,看情况用
Arrays打印
这里还可以借助Java操作数组的工具类Arrays
来打印数组
将参数的数组以字符串的形式输出
import java.util.Arrays;
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Arrays.toString(array);
可以看到把array
这个数组作为参数然后打印了出来
而且还自带[]
2.数组作为方法的参数(重点)
这里先简单讲一点JVM的内容,到后面JVM章节再深入讲解
Java虚拟机栈
:就是我们平常说的栈
本地方法栈
:跑C/C++代码。JVM实际上是由C/C++代码实现的一个软件而已,所以一定有一些底层的代码是在这里跑的。
堆
:就是我们平常说的堆,存放一些对象
方法区
:存放一些静态的变量
程序计数器
:存放下一条指令,保证记录下一条指令是要干什么。不能上个厕所回来就不知道接下来要干什么吧
2.1 数组的存储
上面我们创建的数组array
,他在JVM是这样存放的
array
:存放了变量的地址,就是引用变量。我们一般叫做引用,引用指向一个对象。那么这个数组就是一个对象。前面创建的时候也说过。
注意!
看图就很容易理解
引用就相当于C语言的指针嘛,array
是数组名也是引用变量
这样理解虽然可以
但是!千万千万注意,反过来引用可不是数组名
就像C语言的指针。他们在别的地方也会使用
null
和C语言的空指针一样,Java中引用可以指向null
注意C语言是大写的,Java是小写
如果我们去求一个指向null数组的长度
空指针异常:
不指向任何对象,哪有什么长度
同样适用下标也是空指针异常
什么都没有嘛
2.2 方法中的形参数组
在方法中讲到过,实参和形参
那么数组传给方法的,也是地址
有人叫过按引用传递,其实也可以叫做按值传递
到这里可能很多人都会和C语言混,说白了就是给函数传了个值,这个值是数组的地址嘛
不要想的太复杂
改变引用指向的对象
2个引用指向一个对象
那么能不能1个引用指向多个对象?
那肯定是不可能的
人格分裂?一根吸管同时和多杯水?脚踏多条船?什么狗屁渣男
int[] array = new int[]{1,2,3,4,5};
array = new int[10];
array = new int[20];
array = new int[30];
所以,引用只会改变指向的对象,不能指向多个对象
指向的是自然最后一个改变的对象
最后还有一个问题:
引用一定是在栈上吗???
不一定:一个变量在不在栈上,是你变量的性质决定的。如果就是一个局部变量,那就在栈上。如果是实例成员变量,那就不一定在栈上了。
3.数组作为方法的返回值
写一个方法,将数组中的每个元素都乘2
public static void func(int[] array) {
for (int i = 0; i < array.length; i++) {
array[i] = 2 * array[i];
}
}
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
func(array);
System.out.println(Arrays.toString(array));
}
通过前面的内容我们知道,实参和形参他们指向一个对象
那么问题来了,func
这个方法岂不是把原来的数组直接改变了,如果我们不想改变原来的数组呢?
很简单,在方法的内部创建一个新的数组返回来
public static int[] func(int[] array) {
int[] ret = new int[array.length];
//方法中创建一个数组ret
for (int i = 0; i < array.length; i++) {
ret[i] = 2 * array[i];
//把乘2的元素放到ret中
}
return ret;
//返回数组ret
}
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int[] ret2 = func(array);
//接收数组ret
System.out.println(Arrays.toString(ret2));
}
4.数组应用(练习)
关于数组的练习题什么的其实很简单,就不多讲了,想查也很多
这里主要说一下关于数组的拷贝
数组拷贝
数组的拷贝其实可以自己写个方法拷贝
//1.一般拷贝
public static int[] copyArray(int[] array) {
int[] copy = new int[array.length];
for (int i = 0; i < array.length; i++) {
copy[i] = array[i];
}
return copy;
}
当然,Java提供了几个方法
//2.Java提供的拷贝
//2.1 Arrays.copyOf
int[] copy1 = Arrays.copyOf(array, array.length * 2);
//这里长度设置为*2就相当于扩容。注意Java提供的参数类型是int,所以不能输入小数倍数
System.out.println(Arrays.toString(copy1));
//2.2 Arrays.copyOfRange
int[] copy2 = Arrays.copyOfRange(array, 1, 3);
//Range即可以设定部分拷贝,比如从1下标到3下标
System.out.println(Arrays.toString(copy2));
//2.3 System.arraycopy
int[] copy3 = new int[array.length];
System.arraycopy(array, 0, copy3, 0, array.length);
//设定从原数组的几下标开始,到要拷贝的数组下标几开始,长度是多少
//可以查看System.arraycopy的实现好像不完整?其实是只要带了native字样的方法,都已经由C/C++语言实现了,我们是看不到的
//这些方法有一个特点,就是速度快
System.out.println(Arrays.toString(copy3));
//2.4 clone
int[]copy4 = array.clone();
//就直接克隆,产生一个副本
System.out.println(Arrays.toString(copy4));
既然是拷贝,就会有原数组和新数组,那么这里有两个拷贝的概念
深拷贝:修改新数组,原数组不变
浅拷贝:修改新数组,原数组也变
深拷贝或者浅拷贝都是人为实现的。
5.二维数组
注意:一般情况下无论是什么语言,在内存中二维数组的存储其实都是一行,并不是真的是个表格的类型。
也就是说
二维数组本质上也是一维数组,只不过每个元素又是一个一维数组(二维数组属于特殊的一维数组)
创建
基本语法
数据类型[][] 数组名称 = { 初始化数据 };
一般我们可以直接使用{}
直接创建一个几行几列的二维数组,例如2行3列
int[][] array = {{1,2,3},{4,5,6}};
和一维数组一样,在Java中中括号内不能输入数字,除非是不初始化的创建方式
完整写法
数据类型[][] 数组名称 = new 数据类型 [][] { 初始化数据 };
不初始化写法
数据类型[][] 数组名称 = new 数据类型 [行数][列数];
打印
只要记着下标即可
因为是特殊的一维数组,所以可以画一下来理解
那么array.length
就可以知道
System.out.println(array.length);//2
System.out.println(array[0].length);//3
一般打印
for循环就可以使用array.length
和array[i].length
来打印
foreach
打印
其实就很简单
Java提供的方法
和一维数组一样,Java提供了Arrays.deepToString()
,直译也就是深度打印的方法
自动加中括号和逗号
不规则二维数组
这一块就不需要多讲了,一行可能少一个元素嘛,注意使用array.length
时小心空指针即可
小头图版权:《鍾空2》by 阿语:钟离好感10纪念 2021年10月26日中午12点01分 pid:93694598