Java复习-05数组
一、什么是数组呢?
数组指的是一种容器,可以用来存储同种数据类型的多个值
数组容器在存储数据的时候,需要结合隐式转换考虑。
例如: int类型的数组容器中byte short int 类型的数据可以存储但是double、Boolean类型的却不可以,是因为double类型范围比int范围大,Boolean类型与int不是同种数据类型。
例如: double类型的数组容器可以存储byte short int long float double类型的数据,是因为double类型是所有整数和小数类型当中最大的。
建议:容器的类型,和存储的数据类型保持一致
二、格式
格式一:数据类型【]数组名
范例:int[ ] array
格式二:数据类型数组名[]
范例:int array []
三、数组的初始化
初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
数组初始化的两种方式
静态初始化
动态初始化
数组的静态初始化
初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程
完整格式: 数据类型[]数组名= new数据类型[]{元素1,元素2,元素3…};
范例: int[] array = new int[]{ 11,22,33 };
简化格式:数据类型[] 数组名={元素1,元素2,元素3…};
范例:int[] array = { 11,22,33 };
范例:double[] array2 = { 11.1,22.2,33.3};
当我们直接打印数组时,并不会把数组里的内容打印出来,而是打印数组的地址值。
数组的地址值
定义:数组的地址值表示数组在内存中的位置
解释一下地址值的格式含义
例:[D@776ec8df
[: 表示当前是一个数组
D: 表示当前数组里面的元素都是double类型的
@: 表示一个间隔符号。(固定格式)
776ec8df: 才是数组真正的地址值,(十六进制)
平时我们习惯性的会把这个整体叫做数组的地址值。
那我们怎么获取数组元素呢,接着往下看数组元素的访问
数组元素访问
格式:数组名[索引];
索引:也叫做下标,角标。
索引的特点:从0开始,逐个+1增长,连续不间断
用代码来展示
例如:创建一个数组名为arr,存储的数据有{1,2,3,4,5},现在来获取数组中的第3位数字
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
int num = arr[2];// 数组的下标是从0开始所以第三位是2
System.out.println(num);
}
运行结果:
把数组当中数据根据下标进行修改
格式:
数组名[索引]=具体数据/变量;
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
arr[0] = 12;
System.out.println(arr[0]);
}
运行结果:
分析:arr[0] = 12;
是把12赋值给arr数组下标为0的元素,把原来的数值进行覆盖了
细节:一旦覆盖之后,原来的数据就不存在了。
数组遍历
数组遍历:将数组中所有的内容取出来,取出来之后可以(打印,求和,判断…)
注意:遍历指的是取出数据的过程,不要局限的理解为,遍历就是打印!
用代码来演示:
public static void main(String[] args) {
// 定义数组
int[] arr = {1,2,3,4,5};
// 利用循环进行遍历代码
for (int i = 0; i < 5; i++) { // 循环的次数要等于数组的长度,因为i是从0开始所以i要<5
System.out.println(arr[i]); // 打印获取到的值
}
}
运行结果:
关于数组有一个属性可以获取到数组的长度:数组名.length
用代码来演示:
public static void main(String[] args) {
// 定义数组
int[] arr = {1, 2, 3, 4, 5};
System.out.println(arr.length);
}
运行结果:
数据的动态初始化
为什么有数组动态初始化呢?
假如一开始要添加的数据我不确定,那么静态初始化就不能满足需求,所以动态初始化它来了
概念:
动态初始化: 初始化时只指定数组长度,由系统为数组分配初始值。
格式: 数据类型[]数组名=new数据类型[数组长度];
范例: int[ ] arr = new int[3];
特点:在创建的时候,由我们自己指定数组的长度,由虚拟机给出默认的初始化值。
用代码来演示:
public static void main(String[] args) {
// 定义数组
int[] arr = new int[3];// 3是数组的长度
// 添加数据
arr[0]=12;
arr[1]=13;
// 数组的遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
运行结果:
为什么数组最后一个打印的是0呢?
这是因为我们只给数组前两个位置进行了数据的赋值,而最后一个没有赋值,那么打印出来的是int类型的默认初始化值,假如数组是String类型那么它默认初始化值是null打印出来就是null。
数组默认初始化值的规律
整数类型:默认初始化值:0
小数类型:默认初始化值:0.0
布尔类型:默认初始化值: false
引用数据类型:默认初始化值:null
数组动态初始化和静态初始化的区别
动态初始化:手动指定数组长度,由系统给出默认初始化值。
只明确元素个数,不明确具体数值,推荐使用动态初始化
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度。
需求中已经明确了要操作的具体数据,直接静态初始化即可。
注意:数组索引越界异常
代码:
public static void main(String[] args) {
// 定义数组
int[] arr = new int[3];// 3是数组的长度
System.out.println(arr[3]);// 数组的长度为3,下标只有0,1,2没有3此时运行会报数组索引越界异常
}
运行结果:
四、Java内存分配
把JVM拿出来看
注意:
从JDK8开始,取消方法区,新增元空间。把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中。
如下图所示:
各个区域的说明:
-
栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行。
-
堆:存储对象或者数组,new来创建的,都存储在堆内存 。
-
方法区:存储可以运行的class文件 。
-
本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关。
-
寄存器:给CPU使用,和我们开发无关。
我们主要学习堆和栈
下面用代码进行讲解
当程序运行时先执行main方法,main方法加载到堆内存当中
然后开始执行第二行代码:int [] arr = new int[2];
这行代码是由两部分组成:
一部分是等号左边的int [] arr ,它在栈内存中定义了int[ ]类型的变量,变量名arr,那就表示当前的arr它可以表示记录-int类型数组的地址值
一部分是等号右边的new int[2];
等号的右边有new关键字,所以他在堆内存里开辟了一个小空间。因为长度为2所以会有0和1两个索引,因为堆内存当中是有地址值的所以会赋值给左边的arr,arr也可以通过地址值找到堆内存当中的元素
所以当执行到第三行代码时会打印数组的地址值。
执行第四行代码sout(arr[0]);
它会先根据arr找到堆内存当中所对应的空间,然后再通过0索引找到了第一个元素。
执行第五行代码也是同样的道理。
执行第六行代码arr[0] = 11;
就是把11赋值给arr的0索引,首先是通过arr找到右边的小空间,根据下标找到对应的元素最后把11赋值给了0索引对应的元素。此时0索引原来的那个元素就被覆盖了。
执行第七行代码是同样的道理。
执行第8行代码sout( arr[0]);–打印arr数组的第一个元素,因为0索引和1索引所对应的元素已经修改过了所以打印出来的结果是修改后的结果11.
执行第9行代码同理。
执行第11行代码–int[ ] arr2 = {33,44,55};
创建第二个数组,显然这是一个简化的方式省略了new关键字,所以它同样会在堆内存当中开辟一块空间,同时arr2记录的是第二个数组的地址值,堆内存当中开辟的两块内存互不影响相互独立。
所以执行到第12行代码–sout( arr2);时,打印的是堆内存当中第二块内存的地址值
执行到sout( arr2[0]);时,先通过arr2地址值在堆内存当中找到对应的第二个空间再去打印里面的0索引所对应的值。
第14、15行代码同上。
总结:
1.只要是new出来的一定是在堆里面开辟了一个小空间
2.如果new了多次,那么在堆里面有多个小空间,每个小空间中都有各自的数据
当两个数组指向同一个空间的内存图
int[] arr = new int[3];// 3是数组的长度
int[] arr1 = arr;// 将arr的地址值赋值给arr1
如上面代码所示,此时两个数组同时指向了同一个堆内存当中的空间,
那么它们都可以对堆内存当中的那块空间进行操作
public static void main(String[] args) {
// 定义数组
int[] arr = new int[3];// 3是数组的长度
int[] arr1 = arr;
arr[0]=12;
System.out.println(arr1[0]);
}
此时运行结果为12
所以说当两个数组指向同一个小空间时,其中一个数组对小
空间中的值发生了改变,那么其他数组再次访问的时
候都是修改之后的结果了。