Java数组详解(一)
- 前言:
- 一、创建数组及初始化
- 1.数组的创建
- 2.数组的初始化
- 3.数组的使用
- (1).数组中元素的访问
- (2).数组的遍历
- 二、数组的引用类型
- 三、数组的应用
- 1.保存数据
- 2.作为函数的参数
- 2(1).参数传基本数据类型
- 2(2).参数传数组类型(引用数据类型)
- 3.作为函数的返回值
前言:
上节我们讲到了方法的,方法在Java中也是非常重要的内容,那么这期我将为带来Java中的数组的基础和使用的内容
一、创建数组及初始化
1.数组的创建
数组:我们可以将其看成为相同类型元素的一种集合
数组的定义有3种:
java">public class TestDemo {public static void main(String[] args) {//数组定义1int[] array = {1,2,3,4};//int[]是整型数组,array是数组变量(名)//则下标为 0 1 2 3//数组定义2int[] array2 = new int[10];//这种定义是属于定义了一个大小为10的整型数组//上述初始化为动态初始化:通过new关键字//在C语言中,数组通常会是随机值,但是在Java中,这么定义,数组中会是0;//数组定义3int[] array3 = new int[]{1,2,3,4,5,7};//这种定义是指的是给数组进行赋值之后//那么等号后面的int[]中的[]不能进行空间的大小的填写//上述初始化为静态初始化://静态初始化虽然没有指定数组的长度,//编译器在编译时会根据{}中元素个数来确定数组的长度。//静态初始化时, {}中数据类型必须与[]前数据类型一致。//静态初始化可以简写,省去后面的new T[]。T为数据类型//实际中我们不用管那么多,直接写就可以了//静态和动态初始化也可以分为两步,但是省略格式不可以int[] array1;array1 = new int[10];int[] array4;array4 = new int[]{10, 20, 30};//但是我们不可以分两步直接进行赋值//如:int array5;array5 = {1,2,3,4,5,6};//这种会报错,只能在定义是同时赋值System.out.println(array);System.out.println(array2);System.out.println(array3);//打印出来是“地址”,但是它不是真正的地址,这是哈希值,//Java太安全了,但是这个哈希值也是唯一的}
}
" [ " 表示的是数组类型,“ I ”表示的是为整形;
这些地址是放在堆上,引用变量 --> 储存”地址“的变量。
2.数组的初始化
java">// 如果没有对数组进行初始化,数组中元素有其默认值// 如果数组中存储元素类型为基本类型,默认值为基类类型对应的默认值,比如:public static void main2(String[] args) {char[] array1 = new char[10];double[] array3 = new double[10];float[] array4 = new float[10];boolean[] array5 = new boolean[10];//布尔初始化,值全为初始化为falseString[] string = new String[10];//string类型数组初始化全为null//string为引用类型}
3.数组的使用
(1).数组中元素的访问
java"> public static void main3(String[] args) {int[]array = new int[]{1, 2, 3, 4};array[0] = 100;//可以直接而对于某一项那个值去修改System.out.println(array[0]);System.out.println(array[1]);System.out.println(array[2]);System.out.println(array[3]);//System.out.println(array[4]);//数组没有第五个元素,所以下标4就代表越界访问
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
// at TestDemo.main(TestDemo.java:69)
// Disconnected from the target VM, address: '127.0.0.1:49482', transport: 'sock//这个异常是代表数组越界访问的异常System.out.println(array.length);//C语言中得用sizeof来计算数组的长度,Java不用//int sz = sizeof(array) / sizoef(array[0]);//数组的长度//注意事项:
// 1. 数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
// 2. 下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。}
java">public static void main3(String[] args) {int[]array = new int[]{1, 2, 3, 4};array[0] = 100;//可以直接而对于某一项那个值去修改System.out.println(array[0]);System.out.println(array[1]);System.out.println(array[2]);System.out.println(array[3]);System.out.println(array[4]);
}
这个时候就出现了异常:数组没有第五个元素,所以下标4就代表越界访问
这个异常代表数组越界访问
注意事项:
数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常
(2).数组的遍历
java">public static void main(String[] args) {int[] array1 = new int[]{1,2,3,4,5,6,7,8};//数组的遍历for (int i = 0; i < array1.length; i++) {System.out.print(array1[i] + " ");}System.out.println();//换行回车//范围for语法for each//这种语法我们拿不到数组元素的下标for (int x: array1) {System.out.print(x+" ");}System.out.println();
}//对于下标的依赖,看情况和个人
二、数组的引用类型
引用类型:什么叫引用类型,在这个变量中,储存的是"地址”
JVM将内存划分几个区:
1.方法区,2.虚拟机区,3.本地方法栈区,4.堆,5.程序计数器
在Java SE 中我们需要重点了解堆和虚拟机区
平时所说的栈,其实指的就是Java虚拟机栈
如:局部变量存在栈里
堆:一般用来存储对象的
本地方法栈一般使用C语言和C++来写的
堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),
堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。
每一块内存都有自己的使命,堆和方法区是所有线程共享的数据区 本地方法栈和虚拟机区以及程序计数器是处于线程隔离区
java">public static void func() {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;array2[4] = 500;
}
谈一下对这段代码的理解:
首先这个数组1,在main方法中,先指向了堆中的数组1的对象,分别是10,20,30;假设这个对象的地址是0x18,虚拟机上的main方法栈中保存了array1这些地址,array2定义为了1,2,3,4,5;这时候堆中array2的对象的值1,2,3,4,5;但是又对array2[0]和[1]修改,所以这时候堆中array2的对象的值变成了100,200,3,4,5;再通过了array1=array2赋值,假设array2的地址是0x78,所以虚拟机中的main方法栈中两者的保留的地址均是0x78.所以这个时候array2的对象中的值就会变成了100,200,300,400,500。所以这两个引用均同时指向了一个对象,所以不管通过哪个引用,都可以把数组对象当中的值进行修改,那么array1的对象10,20,30,没有人再指向它了,那么JVM会自动把它回收掉 ;当func方法执行完毕,此时array1和array2是局部变量,此时就会被回收,那么array2所指向的对象没有其它引用所指向的,所以它也会被JVM而自动回收掉
java"> //null 在 Java 中表示 "空引用" , 也就是一个不指向对象的引用.public static void main3(String[] args) {//null//int[] array = 0;//通常把数组直接赋值为0是错误的//因为它指的是引用类型,而零是整数类型,两者是不同的int[] array3 = null;//array3这个引用不指向任何对象System.out.println(array3.length);//这个时候会发生报错,因为array3不指向任何数组对象,所以也就无法就计算长度//这个时候就会出现空指针异常的报错提醒:NullPointerException//这个异常会伴随你的一生在我们学习过程中//如果以后遇到空指针异常那么我们需要定位,看看那个引用是空的}
三、数组的应用
1.保存数据
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] + " ");}
}
2.作为函数的参数
2(1).参数传基本数据类型
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);
}
总结: 发现在func方法中修改形参 x 的值, 不影响实参的 num 值。
2(2).参数传数组类型(引用数据类型)
java">/*** 这种是改变了形参的指向(引用)* 在这种情况下,并不会影响到实参的指向*/public static void func1(int[] array) {array = new int[10];//属于是对数组重新创建一个,这时候就会是改变了形参的指向}/*** 这时候是array得到了array2的地址,* 那么这个形参的array指向了栈上array2的对象,* 所以这个时候改变了形参array的数值,地址一样,那么也就是两者指向了一个对象* 所以对谁修改都会改变最后的对象的值* @param array*/public static void func2(int[] array) {array[0] = 99;}//总结: 所谓的 "引用" 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实//只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).public static void main(String[] args) {int[] array1 = {1,2,3,4};func1(array1);for (int i = 0; i < array1.length; i++) {System.out.print(array1[i] + " ");}System.out.println();int[] array2 = {1,2,3,4};func2(array2);for (int i = 0; i < array2.length; i++) {System.out.print(array2[i] + " ");}System.out.println();}//总结: func1也就是改变了形参的指向(引用)//当然,你不要以为传了引用,就万事大吉了,你要想想你拿引用干些什么了
func1在我原来的理解或许会打印为1,2,3,4,0,0···等
因为array1在main方法中,所以他会创建了array1,来保存它指向的地址,这个引用会指向array1的对象
但是当它进入到func1中,这时候也会在虚拟机的栈的func1方法上创建一个array(理解为载体),在array中存进的array1(是地址)指向的对象也没有发生变化,
但是这个时候func1我们会创建一个新的变量array(这个array的地址存进了那个载体中去),那么来储存array1(地址)的array(载体)的指向的对象就会发生变化,
那么它储存的地址也就会发生变化。所以最后的通过的func1的方法array1没有什么变化(其实变化也跟它没有相关的),所以最后是1,2,3,4.
其实一句话:就是改变了形参的指向,要不变,就是原来的,要不是原来的,那就是改变了指向的对象
说了这么多:我的理解,类比C语言的指针,array[数字],是对于同一块内存的中的内容发生改变,就是*p
array指向的改变,是地址的改变,即是从p = &a 改变到了 p = &b。
3.作为函数的返回值
java">/*** 在这个方法中首先创建了一个数组,在堆上就会显示它的对象的值,此时通过引用获得了地址,这个地址存在了虚拟机栈上* 再通过return,返回的array的地址* @return*/public static int[] func3 (){int[] array = new int[]{1,2,3,4,5,6};return array;}public static void main(String[] args) {int[] ret = func3();//再通过ret接受func3所返回的array的地址,这时候通过地址指向了array的对象for (int i = 0; i < ret.length; i++) {System.out.print(ret[i] + " ");}//对象一定是在堆上,但是引用变量不一定是在栈上(后期会讲)}
好了,这节我们先到这里,下一期博主将会为大家带来Java中的数组快速操作的方法及二维数组,当然,这节内容上如果有哪些地方的不足,欢迎大家在评论区指出!