一、数组基础知识:
1、什么是数组:
数组是一种线性数据结构,是一个使用连续的内存空间存放相同的数据类型的集合容器,与其他容器相比,数组的区别主要在于性能与保存基本类型的能力。
在Java中,数组是一种效率最高的存储和随机访问对象的方式,通过寻址公式,随机访问的时间复杂可以达到O(1),但是为了保持空间的连续性,在数组中插入、删除数据时,都需要移动后面数据,该操作的时间复杂度为O(n)。另外,由于空间上连续,所以数组对CPU缓存比较友好,借助CPU的缓存机制,预读数组中的数据,提高访问效率。但是,由于数组是定长的,一旦声明之后就不可以改变长度,所以如果长度声明过大或者过小都会造成问题。
数组可以自动给数组中的元素从0开始编号,方便操作这些元素。数组属于引用变量,并且数组的长度是固定的,数组的使用有四个步骤,声明数组,分配空间,赋值,处理。
2、一维数组的声明与创建:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};
元素类型[] 数组名 = {元素,元素,……};
示例:int[] arr = new int[5];
int[] arr = new int[]{3,5,1,7};
int[] arr = {3,5,1,7};
注意:给数组分配空间时,必须指定数组能够存储的元素个数来确定数组大小。创建数组之后不能修改数组的大小。可以使用length 属性获取数组的大小。
3、数组的初始化:
4、数组的常见异常:
(1)ArrayIndexOutOfBoundsException 索引值越界。
原因:访问了不存在的索引值:
(2)NullPointerException 空指针异常:
原因: 引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法。
5、数组内存分析:
6、Arrays的使用:
遍历: toString() 将数组的元素以字符串的形式返回
排序: sort() 将数组按照升序排列
查找: binarySearch()在指定数组中查找指定元素,返回元素的索引,如果没有找到返回(-插入点-1) 注意:使用查找的功能的时候,数组一定要先排序。
7、二维数组:
(1)二维数组定义:数组类型[][] 数组名 = new 数组类型[一维数组的个数][每一个一维数组中元素的个数];
疑问: 为什么a.length = 3, a[0].length = 4?
(2)二维数组的初始化:
二、数组提高:
1、数组的特点:
在java中有很多方式来存储一列数据,而且在操作上面比数组方便的多?但为什么我们还需要使用数组,而不是替代它呢?
数组与其他种类的容器之间的区别有三个方面呢:效率、类型和保存基本类型的能力。在Java中,数组是一种效率最高的存储和随机访问对象引用序列的方式。
数组确实是没有List、Set这些集合使用方便,但是在某些方面数组还是存在一些优势的,例如:速度,而且集合类的底层也都是通过数组来实现的。
(1)例子:数组和list求和操作的比较:
从上面的时间消耗上面来说数组对于基本类型的求和计算的速度是集合的5倍左右。其实在list集合中,求和当中有一个致命的动作:list.get(i)。这个动作是进行拆箱动作,Integer对象通过intValue方法自动转换成一个int基本类型,在这里就产生了不必要的性能消耗。
所以在性能要求较高的场景中请优先考虑数组。
2、变长数组:
数组是定长的,一旦初始化声明后是不可以改变长度的。一旦初始化声明后是不可改变长度的。这对我们在实际开发中是非常不方便的,聪明的我们肯定是可以找到方法来实现的。
那么如何来实现变长数组呢?我们可以利用List集合add方法里面的扩容思路来模拟实现。下面是ArrayList的扩容方法:
它的思路是将原始数组拷贝到新数组中,新数组是原始数组长度的1.5倍。所以模拟的数组扩容代码如下:
通过这种迂回的方式我们可以实现数组的扩容。因此在项目中如果确实需要变长的数据集,数组也是在考虑范围之内的,我们不能因为他是固定长度而排斥他!
3、数组复制问题:
前在做集合拷贝的时候由于集合没有拷贝的方法,所以一个一个的复制是非常麻烦的,所以我就干脆使用List.toArray()方法转换成数组然后再通过Arrays.copyOf拷贝,在转换成集合,个人觉得非常方便,殊不知我已经陷入了其中的陷进!我们知道若数组元素为对象,则数组里面数据是对象引用。
从结果中发现,persons1中的值也发生了改变,这是典型的浅拷贝问题。所以通过Arrays.copyOf()方法产生的数组是一个浅拷贝。同时数组的clone()方法也是,集合的clone()方法也是,所以我们在使用拷贝方法的同时一定要注意浅拷贝这问题。
4、数组转换为List注意的地方:
(1)我们经常需要使用到Arrays这个工具的asList()方法将其转换成列表。方便是方便,但是有时候会出现莫名其妙的问题。如下:
结果是1,是的你没有看错, 结果就是1。但是为什么会是1而不是5呢?先看asList()的源码:
注意这个参数:T…a,这个参数是一个泛型的变长参数,我们知道基本数据类型是不可能泛型化的,也是就说8个基本数据类型是不可作为泛型参数的,但是为什么编译器没有报错呢?这是因为在java中,数组会当做一个对象来处理,它是可以泛型的,所以我们的程序是把一个int型的数组作为了T的类型,所以在转换之后List中就只会存在一个类型为int数组的元素了。所以我们这样的程序System.out.println(datas.equals(list.get(0)));输出结果肯定是true。当然如果将int改为Integer,则长度就会变成5了。
(2)我们再看下面程序:
这个程序非常简单,就是讲一个数组转换成list,然后改变集合中值,但是运行呢?
编译没错,但是运行竟然出现了异常错误!UnsupportedOperationException ,当不支持请求的操作时,就会抛出该异常。从某种程度上来说就是不支持add方法,我们知道这是不可能的!什么原因引起这个异常呢?先看asList()java零基础学数组的源代码:
这里是直接返回一个ArrayList对象返回,但是注意这个ArrayList并不是java.util.ArrayList,而是Arrays工具类的一个内之类:
但是这个内部类并没有提供add()方法,那么查看父类:
这里父类仅仅只是提供了方法,方法的具体实现却没有,所以具体的实现需要子类自己来提供,但是非常遗憾这个内部类ArrayList并没有提高add的实现方法。在ArrayList中,它主要提供了如下几个方法:
1、size:元素数量
2、toArray:转换为数组,实现了数组的浅拷贝。
3、get:获得指定元素。
4、contains:是否包含某元素。
所以综上所述,asList返回的是一个长度不可变的列表。数组是多长,转换成的列表是多长,我们是无法通过add、remove来增加或者减少其长度的。
参考文章:
java数组详解_oguro的博客-CSDN博客_java数组
java提高篇(十九)-----数组之二_Java 技术驿站的博客-CSDN博客
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/19929.html