在看之前,可以给作者一个免费的点赞嘛!如果能加一个关注就更好了!!!
纪要:本文将对于引用类型,Java内一维数组的创建和使用,二维数组的创建,引用和不规则二维数组进行一个较为深入的了解。
目录
接下来让我们开启正文。
先导:引用类型
数组对于每一个编程语言都是非常重要的数据结构,在C语言中如此,在Java中依然如此。但是,跟C不一样的是,Java讲数据类型分成了两个大类,一个是基本数据类型,另一个则是引用类型。而不难看出,除开Java内的8种基本数据类型,剩下的数据类型则都叫引用类型,而如果正在阅读本文的读者将来如果要持续深入的学习Java,那么,后续在提到除基本数据类型之外的数据变量,那么无论是从业者,或者是与之相关的文章都会简称他们为引用,本文也会在后面的某些地方称数组为引用。
既然我们已经知道了引用是除基本数据类型以外的其它数据类型,那么我们心中一定会有一个疑问,引用类型的变量和基本变量在数据存储上有什么区别。我们先给出结论。
引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象。而基本变量,则在内存中直接存储他们的本身的值。
至于什么是堆,内存中还有其他什么区域,等我们讲完数组的内容之后,我们再来细说。
1.Java内一维数组的创建和使用
1.1 一维数组的创建
在Java中,不难发现在数组的定义中,C语言和Java有着很大的区别。
现在我想创建一个数组,里面存放整数1,2,3,这个代码在Java中应该如何写呢?
int[] array = {1, 2, 3};
就这么简单的一行代码,一个长度为3的数组就被我们创建好了。但是如果细看,会发现在C中位于int和【】符号之间的数组名移到了后面,如果你尝试和C语言一样的写法(因为这里的int[]是数据类型!!!,你把数组名放到中间就会让其他人引起歧义,尤其是没学过C的),代码可以通过编译,但是不推荐这种写法!!!
可是在写代码解决问题的时候,我们有的时候并不能在一开始就知道数组内应该存放什么内容,只知道数组的长度是多少,那么这个时候应该怎么写代码呢?难道是在【】内加上数字???
答案是不对的,现在我们来创建一个长度为5的数组,但是不对这个这个数组进行赋值。
int[] array = new int[5];
正确的代码如上图所示。但是你看了这个代码会更疑惑,这个new是啥东西???为什么代码得这么写,我们先埋一个坑,等到后续的“类与对象”这篇文章写完了,你就知道了new在这里的意思,先记住如果你不知道数组中应该存放什么数据,或者暂时不需要往数组里存放元素,这么写就完了~~~
我们写了两种可以创建数组的方法,第一种不指定长度,直接进行初始化和赋值,第二种只进行初始化,但是不进行赋值,接下来,还有一种创建数组的方式,下面我们来区分一下第二种和第三种方式的区别。
1.1.1 静态初始化和动态初始化
刚刚我们提到的第三种方法,是这么初始化数组的。
int[] array = new int[] {1, 2, 3};
这种方式初始化也是正确的,在Java中,我们称其为静态初始化。为什么把这种初始化作为静态,我个人的理解是整个数组长度是由{}内的元素个数确定的,可能这样更为静态吧。
静态初始化数组有一些事项值得注意。
静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。
静态初始化时, {}中数据类型必须与[]前数据类型一致。
但是但是,我们看第一种创建数组的方式,数组的长度是3,我们没有给数组的长度,但是也没有new int[]这样的关键字。事实上,第一种写法是第二种写法的简写。
而第三种创建数组的方法则被称作动态初始化数组。但是动态化初始数组的时候需要注意,由于数组并没有进行赋值,按照C语言的标准,此时数组中存放的值是没有意义的随机值,并不能完成业务,但是Java会在动态初始化的数组中存放默认值(这个点非常重要,记住咯!!!),那么各个数据类型对应的默认值如下表。
如果数组中存储元素类型为引用类型,默认值为null
在这里再跟各位补充一下,在Java中,数组的创建其实可以分成两步写,先对数组进行声明,在初始化也是可以的,就像这样。
int[] arr1;
arr1 = new int[]{1, 2, 3};
int[] arr2;
arr2 = new int[5];
但是,最重要的是,new int[]一定不能缺!!!缺了就错了!!!
1.2 一维数组的使用
既然我们创建了数组,那么我们一定要使用它,不然创建了不用来浪费我们的内存空间嘛???
而在数组中我们最常用的就是遍历,在Java中,除了和C语言中通过for循环来遍历数组的方式之外,我们还有一种特殊的方式,叫做for-each
foreach的语法如下
for(元素类型t 元素变量x : 遍历对象obj){ 引用了x的java语句; }
我们举一个例子,大家就理解了他的语法。
int[] array = {1, 2, 3};
for (int x : array) {
System.out.println(x);
}
很明显,由于数组array是int类型,所以foreach循环中的“元素类型t”是int,而x就是指代的数组中的元素而已,:后面的数组array就是我要遍历的对象,而{}内的语句就是我要对array数组的操作。
同样明显的是,对于for循环的三个条件,我们发现foreach循环不能控制循环的次数,就只能是从头到尾进行遍历,而for循环则可以更加灵活的访问数组(在保证数组下标不会越界的情况下)。通过对比for循环和foreach循环对比数组的差异,我们可以得到如下结论。
如果对循环次数不确定,对于控制条件不确定,需要从头到尾遍历数组的,foreach循环更佳。
而对于循环次数十分确定,不需要完全遍历数组的,for循环更佳。
1.3 数组在内存中的存储(填坑环节)
如果我们想对于数组有一个更好的理解,那么我们就要知道数组在内存中是是如何存储的。
在Java中,数组是如何在内存中存储的呢?
首先我们得来看看在Java的眼中,计算机内存长啥样。
这个图片生动的解释了在Java眼中计算机的内存长什么样。而在目前的学习深度来说,我们暂时只需要了解虚拟机栈和堆,后期我们在进行详细的讲解。
在C语言中,我们知道在存放数组的时候,我们会在栈区(显然不是Java内的这几个栈)开辟一块连续的空间,用来存放数组。
但是在Java中,如果我们创建了一个数组,我们首先会在虚拟机栈上创建一块空间,这个空间存储一个地址,而同时会在堆区开辟一块空间,这个空间用于存放数组中的元素。
如果我们画个图,那么就是这样。(堆确实比栈要大一点)
我们来看,首先,IDEA读代码,发现你创建了一个array数组,这个时候先在栈区开辟一款空间,用于存储堆上的地址,然后在堆区上在开辟一块空间,存数组里的元素,存完了,再将堆区的地址返回到栈区上。就像图片里画的那样。但是栈和堆上的地址开辟是由编译器和CPU决定的,两者并无特定的联系。
2. 二维数组
2.1 二维数组的创建
既然我们一维数组讲完了,那么二维数组怎么创建呢?
按照我们前面讲的,同时辅佐我们在C语言的知识,二维数组的创建,应该长这样。
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int[][] arr2 = new int[2][3];
int[][] arr3 = new int[][]{{1,2,3},{4,5,6}};
2.2 二维数组的存储
我们搞清楚二维数组怎么存储,那么二维数组怎么使用我们就很清楚了。
我们还是上图片。
你看看二维数组array1,首先,因为他是一个2x3的数组,所以,对比于一维数组,我们在堆区就得开辟两个空间,用于单独存放数组的每一行(数组有几行就开辟几个相同大小的空间)。那么,在栈区是不是也得开辟两个空间,来存放堆区的地址(堆区的地址并不连续,所以要开辟两个空间)。
那么怎么使用,我想你对着这个图,就知道了。array1代表什么,array1[i]代表什么,array1[i][j]代表什么。
2.3 不规则二维数组
不同于C语言,二维数组在Java中可以不规则,即数组每行的元素个数可以不一样。但是不规则的二维数组在初始化时需要注意,需要规定行数,但是列可以省略。
例如这样
int[][] array = new int[2][];
array[0] = new int[]{1, 2, 3};
array[1] = new int[]{4, 5, 6, 7, 8, 9};
至于怎么存储的,跟规则的二维数组一模一样!!!
文章到这里就结束了,你都看到这里了,可以给作者一个免费的点赞嘛!如果能加一个关注就更好了!!!