目录
本章的目标:
🎈数组的基本概念
🍭创建数组
🍭数组的初始化
🍭数组的使用
👉数组中元素访问
👉遍历数组
🎈数组是引用类型
🍭初始JVM的内存分布
🍭基本类型变量与引用类型变量的区别
👉基本数据类型变量
👉引用数据类型变量
🚩再谈引用变量
🍭认识null
🎈数组的应用场景
🍭保存数据
🍭作为函数的参数
🍭作为函数的返回值
本章的目标:
🎈数组的基本概念
- 1. 数组中存放的元素其类型相同
- 2. 数组的空间是连在一起的
- 3. 每个空间有自己的编号,其实位置的编号为0,即数组的下标。
🍭创建数组
T[] 数组名 = new T[N];
T:表示数组中存放元素的类型
T[]:表示数组的类型
N:表示数组的长度
public static void main(String[] args) {
int[] array1=new int[5]; //创建一个可以容纳5个int类型元素的数组
double[] array2=new double[5];// 创建一个可以容纳5个double类型元素的数组
float[] array3=new float[5];// 创建一个可以容纳5个float类型元素的数组
}
我们可以对比c语言的创建数组,int arr[N]={0,1,2};
java创建数组是 int[] arr=new int[N];
其实我们更可以看到java 更能理解,因为arr是数组名,它是Int[]类型是数组arr的类型,而c语言中arr是数组名,int是数组里面的值的类型,并不是数组的类型,数组的类型是int[]。
该种定义方式不太友好,容易造成数组的类型就是 int 的误解[] 如果在类型之后,就表示数组类型,因此 int[] 结合在一块写意思更清晰。
🍭数组的初始化
静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定
语法格式: T[] 数组名称 = {data1, data2, data3, ..., datan};
int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9};//静态 double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};//静态 String[] array3 = new String[]{"hell", "Java", "!!!"};//静态
int [] array = new int [ 10 ];int[] array1 = new int[10];//动态 double[] array2 = new double[10];//动态 String[] array3 = new String[10];//动态
【注意事项】
- 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。
- 注意:在数组中可以通过 数组对象.length 来获取数组的长度
- 静态初始化时, {}中数据类型必须与[]前数据类型一致。
- 静态初始化可以简写,省去后面的new T[]。
int[] array={1,2,3,4};//静态初始化可以省略new T[];
- 静态和动态初始化也可以分为两步,但是省略格式不可以
int[] array; array=new int[10];//静态初始化的拆分 int[] array1; array1=new int[]{1,2,3,4};//动态初始化的拆分
这里就不能省略new.
- 如果没有对数组进行初始化,数组中元素有其默认值
- 如果数组中存储元素类型为基类类型,默认值为基类类型对应的默认值
- 如果数组中存储元素类型为引用类型,默认值为null
在一般实际的做题目中,我们用到的最多的是int[] arr=new int[N],因为这样会给默认值,然后开辟了N个长度的数组,然后我们依次赋值。
🍭数组的使用
👉数组中元素访问
【注意事项】1.数组是一段连续的内存空间,因此 支持随机访问,即通过下标访问快速访问数组中任意位置的元素2. 下标从 0 开始,介于 [0, N )之间不包含 N , N 为元素个数,不能越界,否则会报出下标越界异常。所以访问数组的下标不能到array[array.length],不能取到长度。
👉遍历数组
所谓 "遍历" 是指将数组中的所有元素都访问一遍, 访问是指对数组中的元素进行某种操作,比如:打印。
- for-i遍历数组
- 使用 for-each 遍历数组
俩者的不同之处是
- for-i 可以访问到下标,如果对数组中的第二位置的值+1,那么就可以用for-i,则不可以使用for-each。
- for-each不可以访问到下标,不需要取到特定的值即可用。
- 借用Java本身提供的一些方法来实现数组的打印
这里首先需要介绍一个 工具类(可以理解为C语言里面的头文件):Arrays
其主要作用是:帮助对数组进行一个操作(详情可查找帮助手册)
我们可以再成长手册或者这里可以看到有很多类型的数组,这里就表示重载,后面我会详细说。现在可以理解为哪种数组类型就调用哪个哪个。这里是int类型那么我们就toString(int[] a).
这里用数组转换成字符串形式,我们可以看到加了[],为啥会加[]我们可以再toString中ctrl+鼠标左键,进入源码中查看
现在我们并不能完整的看懂这段底层实现的代码,我们可以根据现象直接实现,[1,2,3]这种形式,我们自己实现一下。
public static void myString(int[] array) { System.out.print("["); for(int i=0;i<array.length;i++) { if(i!=array.length-1) { System.out.print(array[i]+","); } else System.out.print(array[i]); } System.out.print("]"); } public static void main(String[] args) { int[] array={1,2,3,4}; myString(array); }
🎈数组是引用类型
🍭初始JVM的内存分布
而现在我们只简单关心堆 和 虚拟机栈这两块空间,后序JVM中还会更详细介绍。
- 虚拟机栈(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含 有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一 些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
- 堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。
🍭基本类型变量与引用类型变量的区别
- 基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
- 引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址
👉基本数据类型变量
👉引用数据类型变量
我们大标题是数组是引用数据类型 ,我们就根据数据来阐述。
我们可以通过ox77的地址找到对象。这里的array是变量(引用变量,存储的是对象的地址),引用(指向)一个数组对象。这个数组对象在堆区,我们需要存储这个对象的地址,所以array这个变量存储了,叫做引用变量。
🚩再谈引用变量
我们现在给引用变量修改值或者一个数组给另一个数组是如何运行的。
场景1
这个底层是如何实现的呢?
array引用变量存储的是数组对象的首元素的地址,都初始化成默认值0,然后我们对下标为0和下标为1的位置对应的值进行改变,还是对堆上的空间进行改变,array并没有新开一个空间。所以最终array前后打印的值是不一样的。
场景2
这个场景可能有些迷了,array1和array2该输出什么呢?我们一步一步的分析。
场景3
由于array1的空间给了array2,那么对array1的改变,array2也改变了。
场景四
🍭认识null
null 在 Java 中表示 "空引用" , 即:一个不指向对象的引用。
🎈数组的应用场景
🍭保存数据
public static void main(String[] args) {
int[] array = {1, 2, 3};
for(int i = 0; i < array.length; ++i){
System.out.println(array[i] + " ");
}
}
🍭作为函数的参数
我们调用func1,首先a引用变量存放ox13的地址,再调用这个函数是arr也指向a的空间,然后arr开辟一个空间,地址是0x99,然后arr指向了地址为0x99的空间,但是a指向的空间并没有改变。所以打印的结果还是1,2,3,4。
调用func2呢?
a引用变量存的是0x13的地址,指向了一块空间,调用func2,也指向了这块空间,然后arr对0位置进行改变,就是相当于对这片空间的下标为0的位置改变。
上面俩种调用
- 第一种修改了自己的指向(因为自己开了一块空间),自己是形参,所以对自己的修改并不会影响实参的修改。
- 第二种修改指向的对象里的值,所以改变指向的对象里面的值,就会改变实参的值。
这下面很明显是修改指向的对象里的值,自己没有开空间,所以改变了实参的值。
总结: 所谓的 "引用" 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实 只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).
🍭作为函数的返回值
今天张老师很讨厌!