欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

来吧!给你不一样的数组深入讲解

程序员文章站 2024-01-20 09:41:04
...

不知道为啥,数组让我写的很痛苦!写到深夜两点啊,不容易,各位看官,记得点赞????,不然没动力了

数组小谈????

庆哥: 嗨,小白,知道啥是数组吗?????小白: 你看你这话说的,数组那还不简单,学计算机的没有不知道数组的吧,我们刚开始接触C语言的时候就有数组啊,现在在学习java,也有数组啊,一般不就这样嘛????

int[] array = new int[10]

这就创建了一个长度为10的数组,是不是?????

庆哥: 嗯嗯,你还知道数组的啥啊。比如特性啥的?

小白: 这个嘛,数组啊,最经典的不就是可以根据数组下标来读取数据吗?比如上面定义的那个长度为10的数组,可以使用array[1]来获得数组第二个位置的数据。

庆哥: 为啥不是第一个的数据,那不是1吗?

小白: 这个嘛,那是因为数组下标是从0开始的,所以实际上1就是2的位置,就像这样:

来吧!给你不一样的数组深入讲解庆哥: 那数组下标为啥从0开始啊????

小白: 嗯。。。这个?????不知道

庆哥: 在Java中数组其实可以看做是一个对象嘛?????

小白: 纳尼?没有考虑过这个问题啊????

庆哥: 知道Array和Arrays嘛????

小白: 不是太清楚????

庆哥: 哈哈,来吧,今天就让你彻底搞懂数组这家伙????

小白: 小板凳已备好????

啥是数组啊????

天马星空看数组????

庆哥: 既然我们要学习数组,那首要的任务就是先要弄懂,啥是数组?你现在清空大脑,不要想着什么数组是数据结构,什么连续内存,什么随机访问,什么不可变的,抛出你之前关于数组的所有认知,从零开始,你想想,数组是个啥?????

小白: 那我要发挥我超强的想象力了哦????,数组嘛,单从这俩字啊,我想着这玩意应该是个跟棍似的????,一组一组的嘛,长长的????,然后是数据嘛,人家是数组,那应该就是跟数据有关的,组?我们平常会说一组一组的,比如几人一组,那这个数组就是一些数据在一块。。。。我在说啥????

庆哥: 可以啊,你这想象力????,那我来说下我的理解吧,初看数组这货,我就觉得啊,它在java中应该也是个类,然后我们也可以通过最基本的new来创建一个数组,刚开始就这样感觉得,但是谁知道这家伙完全不按照套路出牌啊????

小白: 你这样一说也真是的,我本来也以为数组可以使用new嘞,有的时候还是有点疑惑的,特别是遇到Array这个类就更迷惑了????

庆哥: 的确,我刚开始也是这样,觉得这个Array不就是数组嘛,然后我还这样试过????

来吧!给你不一样的数组深入讲解哈哈,我当时还迷惑,这是咋回事啊,这不是创建数组嘛????

小白: 这是咋回事啊,为啥会报错啊????

庆哥: 这个嘛,我们看看Array的源码就知道了来吧!给你不一样的数组深入讲解看到了吧,它的构造方法是私有的,所以是不能被实例化的,因为我们使用new就是通过构造方法去创建啊,而这里是私有的,所以是不行滴,知道了吧????

小白: 嗯嗯,看来我对这个数组还真的是不了解啊????,庆哥这次要好好和我说说????

java中的数组

庆哥: 没问题????,那我们言归正传,看看java中的数组到底是个啥,在java中啊,我们可以这样理解数组:

数组这家伙就是一个数据集合,而且它还是有序的,就是很多数据搁在一块,一个挨着一个,而且每个数据的类型都是相同的

这里简单大白话说了啥是数组,有必要还是画个图,来加深下印象,对了对了,之前画了个图,就用这个

来吧!给你不一样的数组深入讲解好了,现在对于数组,给你文字说了是啥,现在再看个图,这里就相当于有一个数组,这个数组有10个数据,你看他们是不是一个挨着一个,然后每个数据还有一个下标,这个下标就相当于给每个数据进行编号,你想啊,编号有啥好处?

是不是更加容易寻找了,对号入座嘛!所以这里就引出了数组的一个大大的特点:

人家支持随机访问啊

小白:  这个是不是就是可以使用下标访问数据的特性????

庆哥: 嗯嗯,是的,我们接着来说,我们现在对数组有个大致印象, ,要知道数组最终是用来干嘛的。人家是用来存放数据的,我们还是先来看看数组的的相关代码吧:

int[] a = new int[10];

看,这就创建了一个数组,不是我们想的使用new的方式,其实从代码我们就能猜到,这个数组的长度是10,啥意思,数组人家是有长度的。

小白: 这个是必须要给它指定一个长度吧

数组的声明

庆哥: 这个就牵涉到数组的声明了,数组是用来存放数据的,那我们要用它的话就要先创造它吧,之前说了,人家不是使用new,人家是这样的形式

int[] a = new int[10];

那么这样可以吗?

int[] a = new int[];

有啥区别?是不是少了个10,行吗这样,我们看看

来吧!给你不一样的数组深入讲解看到了,不行,为啥不行啊,你想想?

小白: 这个嘛,这里的10是在给数组一个指定的长度吧,难道不能默认长度为0吗?

庆哥: 这里就要看数组的一些特点了,对于数组啊,人家是有序数据的集合,在内存中来展示就是人家需要连续的内存空间,还有一个特点那就是你一旦声明就不会再改变了

小白: 嗯嗯,这个我知道,数组一旦确定将是固定不变的,哦哦,我知道了,那这里就必须要求指定长度了,不然相当于没创建数组啊,长度为0没意义啊????

数组在内存中的分配

庆哥: 对的,我们再看这段代码

int[] a = new int[10];

是个怎么回事,首先我们知道了,这是要创建数组吧,长度也指定了,是10,对了这里忘了说了,这个数组是个整型数组,类型是int,为啥要说这个嘞,等会再详细说,先来看图

来吧!给你不一样的数组深入讲解啥意思嘞?这些个格格就可以看成是内存,一块块的内存,现在我们创建一个长度为10的整型数组,那就需要十块这样的内存空间。

小白: 这里红色的块是啥意思啊?????

庆哥: 红色啊,就代表已经被使用了的内存空间,看出啥问题了没,现在你创建这样的代码

int[] a = new int[10];

意思就是你告诉内存,“内存那家伙,给我来十块内存空间,记住必须连续的哦????”,也就是说,数组申请的内存空间是连续分配的,数组中的数据比较矫情,必须一个挨着一个????

简单聊聊初始化

小白: 嗯嗯,我记得数组的声明不止这一种吧?????

庆哥: 是的,我们之前介绍的这样叫做动态初始化数组,啥意思嘞,就是指定了长度,但是没有给值,我们看这个

 int[] a = new int[10];
  System.out.println(a[2]);

输出是0,你可以试下,这10个数据都是0,这是默认初始化的值,我们也可以使用这样静态初始化

int[] b = new int[]{1, 2, 3};

啥意思,也就是在创建数组的时候就把值给确定下来,你猜猜这样创建的数组长度是多少?

小白:  这个啊,这里没有给定像10那样的数据啊????,这个应该是。。。3吧????,后面大括号有三个数

庆哥: 我们看下这段代码

int[] b = new int[]{1, 2, 3};

        System.out.println(b.length);

这是啥,这是求数组长度的,我们看看输出

来吧!给你不一样的数组深入讲解被你说对了,像这样的,它会根据你大括号里的数据创建内存空间,也就是说有几个数就申请几个内存,不多不少申请了就固定了

数组变量和数组对象

庆哥:  我们上面已经简单介绍完数组了,那你知道什么是数组变量什么是数组对象吗????

小白: 我去,晕菜,这俩双胞胎吧????

庆哥: 那我来说说,啥是数组变量,看之前的代码

int[] a = new int[10]

这个a其实就是一个数组变量,一个数组变量指向一个数组对象,数组变量其实就是一个引用,存放的是内存地址,也就是引用是与内存地址划等号的,内存地址是给计算机看的,而引用是给我们看的(一个我们比较熟悉的符号),而这个a其实是数组的首地址,指向的数组对象其实就是a[0]这个数组变量对应的数组对象。

那数组对象其实就是内存空间中存放的数值了。

数组初始化是对谁初始化

那我们接着这个数组变量和数组对象来讲讲,数组初始化是对谁进行初始化,其实也很简单,知道了什么是数组变量和数组对象之后,我们就应该知道,数组初始化不是对数组变量初始化,而是对数组对象进行初始化。

所谓的对数组对象初始化,无非就是告诉内存,我要创建一个数组,你得给我分配一块连续的内存。

咋样,明白了吧????

小白: ok的????

数组能存储啥????

庆哥: 好了,以上属于数组的基本知识,不多说了,我们接下来再来说说数组的数据存储类型,还记得之前说的吗?数组中的每个元素都是相同的类型,我们上面是int类型的,啥意思嘞?也就是说啊,你创建什么类型的数组就只能存放什么类型的数据。

比如这样就不行

来吧!给你不一样的数组深入讲解因为你创建了是个int整型的,所以只能存放整型数据,字符串就不行,想要存放字符串的话那就要创建一个字符串数组

 String[] strings = new String[]{"hello"};

有个小例外

这里啊,是有个例外的 ,我们看这个:

Object[] objects = new Object[10];
        objects[0] = 1;
        objects[1] = "hello";

这个是都可以的,知道为啥不????

小白: 这个啊,知道,Object可是java中所有类的超类啊????

庆哥: 正解,好了,咱来简单总结下:

Java中的数组是用来存储同一种数据类型的数据结构,一旦初始化完成,在内存中的空间就已经固定了下来

数组是个对象?

庆哥: 你说数组是不是个对象?????

小白: 数组是对象?不是说数组不能用new的方式创建吗,那应该不是吧,感觉和平常的对象不一样啊????

庆哥: 实话告诉你吧,数组啊,其实是个特殊的对象????,只不过数组比较特殊,它不同于一般的对象,像一般的对象都有特定的java类,比如我这里创建了一个Person类,然后有这个代码:

 Person person = new Person();
        System.out.println(person.getClass().getName());

就是创建一个Person对象,然后得到它的类名,如下

来吧!给你不一样的数组深入讲解再来看个

Object object = new Object();
        System.out.println(object.getClass().getName());

这个知道吧,它的类名一定是Object,我们看

来吧!给你不一样的数组深入讲解是吧,我们再来看数组的,它可以这样获得

//数组是特殊的对象,没有对应的类文件,数组类是在运行时产生的,类名很奇怪
        System.out.println(new int[2].getClass().getName());

它这个类是啥嘞

来吧!给你不一样的数组深入讲解

在这里插入图片描述

这是啥玩意????

小白: 我去,这里我是不是只要记住,其实数组也是个特殊的对象就行了吧????、

庆哥: 对的,只需要记住,数组其实也是个对象就行,这可是对数组的深层次理解哦????,那接下来我们继续说数组的两个让人懵圈的类。

Array和Arrays

对这俩货熟悉吗????

小白: 很懵圈啊,之前我还想使用Array来创建数组嘞????

庆哥: 哈哈,使用它创建数组是不行的,话说这俩货是干嘛的啊,太容易让人迷惑了,实际上啊,这俩货的存在都是为了让我们更一步的操作数组的,先来个简单的例子,比如我们创建一个数组

 int[] b = new int[]{1, 2, 3};
        System.out.println(Array.get(b, 1));

看到没,我们平常是使用b[1]来获取下标为1的元素,使用Array就可以像上面那样获取,也就是说Array给我们提供了可以直接操作数组的一些方法,有如下这些:来吧!给你不一样的数组深入讲解小白: 这就是个类似工具类啊,可以方便我们操作数组是吧????

庆哥: 对的,还记得我们之前就说过这个Array吗,它的构造方法是私有的,不能实例化,它的方法也都是静态的,可以直接还用类名来调用,就像上面那样,就是为了我们更加方便的操作数组而存在的。

小白: 这样说的话,那这个Arrays是不是类似啊????

庆哥:  是的,Arrays也是个方便我们操作数组的工具类,只是他们提供的功能有所不同,我们使用Arrays可以实现给数组填充数据,也就是赋值,也可以进行排序啊,进行二分查找啊,截取数组啊之类的????

小白: 这个提供的功能还不少嘞????,使用上是不是和Array类似啊

庆哥: 是的,你看,比如说给数组数据进行排序

System.out.println("排序:");

        int[] array1 = new int[]{5, 7, 8, 9, 1, 3, 6};
        Arrays.sort(array1);

看它提供的方法

来吧!给你不一样的数组深入讲解

在这里插入图片描述

也有很多,需要啥我们用啥就行了

咋样,这样一介绍,是不是发现,其实这俩货也没啥难的啊????、

小白: 是啊,原来就是两个打辅助的啊????

数组的特点

庆哥: 到了这里,你是不是能 总结下数组的一些简单特点啦????

小白: 嗯嗯,数组啊,连续内存分配,可以随机访问,这次刚刚学到的,数组其实是个对象????,对了,数组还有下标,是从0开始的。

庆哥: 嗯嗯,问题来了,为啥要从0开始,你知道吗?

下标索引为啥从0开始

小白: 这个还真不知道,平常就记着下标是从0开始的了,至于为啥是从0开始还真不知道嘞????,为啥啊庆哥。

庆哥: 要弄明白这个问题,要看这个图

来吧!给你不一样的数组深入讲解我们已经知道了,数组的创建需要连续的内存空间,比如这里的整型数组,长度为10,那就再内存开辟了相应的内存空间,在内存空间中,每个内存是有相应的地址的,这个是操作系统干的事,当你申请了内存之后,操作系统会为这块内存地址进行编号。

比如这里申请了一个长度为10的整型数组,我们知道int在java中占4个字节,也就是说一个数据占四个字节的内存,也就是上面的一块.

然后每一块都有相应的内存地址编号,比如0对应的这块,编号是1000-1003,占四个字节嘛,我们接下来结合数组的随机访问,比如我们使用array[0]去访问第一个元素,实际指向的就是1000这个内存地址,这个在数组中也叫作首地址,数组变量array就是指向这个首地址。

这个首地址也叫作base_address,记住这个,然后我们如果要访问下标为1的怎么访问嘞,这里有个寻址公式

array[i] = base_address + i*data_type_size

base_address我们知道是啥了,那data_type_size是啥?其实即使数据类型的字节长度,比如这里的int整型就是4个字节,那data_type_size就是4,我们现在要访问下标为1的数据,代入公式就是:

array[1] = 1000 + 1*4 = 1004

看下,是不是刚好定位到下标为1的那块内存的位置。

你想想,如果索引从1开始,那寻址供视是不是就变成了

array[i] = base_address + (i-1)*data_type_size

这就要多一步操作,浪费性能啊????

咋样明白不????

小白: 嗯嗯,原来是这么回事,终于学会了????

数组的增删改查

庆哥: 嗯嗯,那我们再来看看数组的增删改查,也就是对数组进行的一些基本操作,首首先看看数组增加,我们还看着这个图来说

来吧!给你不一样的数组深入讲解如果我们要增加一个元素的话,怎么办?

小白: 这分几种情况吧,插在最前面,中间和最后。

庆哥: 如果是插在中间呢?发现啥问题没?????

小白: 嗯。。我想想。。数组内存是连续分配的,那要插入一个新的元素,那岂不是要把当前位置的元素以及后面的元素全部后移了,这样才能腾出位置插入当前元素吧????

庆哥: 对的,所以对于数组,不仅是插入,删除也是同样的道理,如果不是尾部操作,都需要进行数组挪动操作。

小白: 那这个就费劲了????

庆哥: 是啊,所以数组啊,插入删除效率并不高,最坏的情况,时间复杂度是O(n),好的情况那就是尾部操作,那就是O(1)了,这个知道吧????

小白: 嗯嗯,知道,那查找效率是不是高啊

庆哥: 这里我觉得大家都有个误区,什么嘞,数组如果是使用下标访问,那自然效率高,可是我们平常查找的话是根据数值也不都是下标啊,这样就需要遍历数组找到我们想要的,这个要明白

小白: 是啊,你这样一说,我倒知道了

数组扩容

庆哥: 对了,想一下,如果数组满了咋办????

小白: 这个啊,数组满了,就无法插入新的元素,这样的话就需要对数组扩容,这个扩容,我想想,数组一旦初始化完成,就是固定不变得,这样的话,是不是需要新创建一个数组啊????

庆哥: 对的,数组一旦初始化完成,在内存中的空间就已经固定了下来,即使某个元素被清空,但其所占的空间依然是保留的,因此数组长度是不能被改变的,要想改变数组的空间就必须进行数组扩容。

小白: 那这个是不是就需要把原数组的数据全部复制过去啊

庆哥: 对的,有如下简单代码来吧!给你不一样的数组深入讲解小白: 哦哦,明白了????

完!!!

ps:数组这块怎么说嘞,反正写的有点痛苦????,现在已经是夜里两点了,先到这吧,如有问题,欢迎大家留言讨论!

感谢阅读  更多高质量编程视频www.shangyepingtai.xin