这一章的复习主要涵盖 数组的基本性质,数组和泛型,java.util.Arrays
工具类。这里整理的都是个人觉得比较重要重新认真分析的东西,不一定全部为基础,如果有不准确的地方,还望大佬从评论区指出,感激不尽。
文章中的所有的自定义的测试都在自己的 java-review
仓库中,本文对应的链接:
dd
数组
性质
java
数组是边界安全的不同于
c++
,当数组的下标越出边界的时候会抛出一个ArrayIndexOutOfBoundsException
数组越界的异常,后来用了c++
才直到java
的好,c++
中越界的时候会得到一个为止的数,数组开小的时候就会出现这样的问题,不会报错可以正常编译运行还有结果,但是结果变得让人匪夷所思,根本不知道错在了哪数组为一级对象
数组的初始化中,出来第一维度以外的维度都彼此独立,相当于一个数组对象中有很多的数组引用的成员变量,引用的初始化可以延时完成。创建了的数组的数组成员都是默认的零值,这也就是为什么使用创建类的数组不会触发类的初始化的原因
数组为一级对象
前面有提到过,数组对象是虚拟机创建的,数组标识符只是一个引用
一个数组对象所持有的所有的数组元素其实就是相当于 一个对象持有的成员变量,他们初始化还非常类似
数组元素的初始化就像是创建一个对象实例的时候,类的所有的成员变量都会被初始化为他们的零值(参考 [java复习]基本类型 那篇文章中类型的零值),数组中的初始化都会被初始化为对应的零值,比如: int
会初始化为 0
,
1 | // java test |
从上面的例子中,可以看出 new
一个数组对象,只需要关注最外层的数组长度就好了,因为数组的内部就相当于一个数组引用,类似于 int[] arr
以 2D 数组
为例,其另一个维度不指定的时候,就相当于了声明了一些数组引用,所以它的另一个维度不需要在声明的时候就马上确定下来,使得 另一个维度的每个数组的长度可以不一样,可以像 arr
一样,在后面进行 arr = new int[5];
这种初始化
泛型与泛型
java
中的泛型和数组不能够很好的结合
类似于泛型容器的创建方式,在前面的泛型中有介绍到
1 | // java test |
Arrays
asList()
Arrays # asList
是一个泛型方法,将一个数组转化为ArrayList<E>
1 | // java 12 source |
这里得到并不是 java.util.ArrayList
,而是 Arrays
的内部类,不同于 java.util.ArrayList
,Arrays
的内部类只实现了 AbstractList
的一部分方法(如图所示),对于类似于 add(E e)
和 remove(E e)
方法并没有进行实现,调用这些方法的时候就会调用父类 AbstractList
中的方法抛出 UnsupportedOperationException
这个运行时异常。
1 | // java 12 source |
我们习惯上称 Arrays # asList
得到的 List
不能进行修改容量的操作,上述就是原因之一,另一个原因就是 Arrays.ArrayList
中用来保存元素的数组为 final E[] a
注定了这个数组是不能够对其容量进行修改,这两点就是 Arrays # asList
得到的容器无法进行关于容量操作的原因。
Arrays.ArrayList
没有实现AbstractList
中的一部分方法,如:AbstarctList # add
、AbstarctList # remove
Arrays.ArrayList
的成员变量final E[] a
为不可变引用,无法改变其指向的数组Arrays.ArrayList # iterator
方法得到的迭代器
copyOf()
将数组复制到一个指定长度的新数组并返回,底层通过
System # arraycopy
来实现
1 | // java 12 source |
Arrays # copyOf
会创建一个newLength
大小的数组,并取original.length
原数组长度和newLength
中的较小值的那一个System # arraycopy
对相同数组进行拷贝的时候前面的已经复制的值不会出现覆盖情况,同样不能越界
1 | // test |