一、数组的定义
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。
二、数组的基本特点
- 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 其元素必须是相同类型,不允许出现混合类型。元素的类型可以是java 支持的任意类型
- 数组类型可以是任何数据类型,包括基本类型和引用类型。
- 数组的元素在堆内存中被分配空间,并且是连续分配的
- 使用new 关键字对数组进行 内存的分配。每个元素都会被jvm 赋予默认值。默认规则:整数:0 浮点数:0.0 字符:\u0000 布尔:false 引用数据类型:null。
- 数组的元素都是有序号的,序号从0开始,0序的。称作数组的下标、索引、角标
三、数组的声明
- 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
- 声明一个数组的时候并没有数组真正被创建。
- 构造一个数组,必须指定长度。
四、数组格式
元素类型[ ] 数组名 = new 元素类型 [元素个数或数组长度]; // int [] arr = new int [3];
- []:代表这是数组类型。
- 数组名:一个合法的标识符,命名规范 和 局部变量 规范一致。
- new:是java的关键字。用来向JVM申请内存的。
- 元素类型[元素个数] :决定了向JVM申请的内存空间的大小。
- 大小:元素类型字节数 * 元素个数。
- 元素的个数:只要是一个合法的java 表达式就可以。 返回一个int 类型的值即可。
五、数组的初始化
静态初始化:
由程序猿自己确定每个数组元素的初始值,而数组的长度则由系统自己决定。
int[] arr = { 1, 2, 3 };// 静态初始化基本类型数组;
动态初始化:
初始化时由程序猿确定数组的长度,而没一个数组元素的值,则由系统来分配初始值
int[] arr = new int[2];//动态初始化数组,先分配空间;
arr[0]=1;//给数组元素赋值;
arr[1]=2;//给数组元素赋值;
六、常用数组的拷贝操作
6.1 System.arraycopy(),我们可以使用它来实现数组之间的复制。其函数原型是:
public static native void arraycopy(Object src,int srcPos,Object dest, int destPos,int length);
* @param src the source array. 源数组
* @param srcPos starting position in the source array. 源数组的起始位置
* @param dest the destination array. 目标数组
* @param destPos starting position in the destination data. 目标数组的起始位置
* @param length the number of array elements to be copied. 复制的长度
需要注意的是在进行数组拷贝时,目标数组必须有足够的空间来存放拷贝的元素,否则就会发生角标越界异常。
6.2 Arrays.copyOf
得到一个新的数组,在复制了original数组中的元素之后,长度还变为newLength。如果长度变长,则填充默认数据。如果长度变短,多的数据就没了
public static int[] copyOf(int[] original, int newLength)
Arrays.copyOfRange
返回一个数组,并且拥有给定数组的指定范围的数据。
public static int[] copyOfRange(int[] original, int from, int to)
其中 copyOf 和 copyOfRange 都会调用 System的一个静态方法 arraycopy。
七、java.util.Arrays
1.Arrays方法分类
- 排序相关
- 查找相关
- 比较相关
- 打印相关
- 计算hashCode
- 拷贝相关
- 赋值相关
- 转化为集合List
- 转换为stream
2.1 排序相关
2.1.1 普通排序
主要是调用静态方法 sort() ,支持基本类型数组,引用类型数组必须实现 Comparable接口。其中的排序算法用的是Dual-Pivot Quicksort(双轴快排),升序排序,时间复杂度为O(n log(n))。
Arrays.sort(int[] a)
Arrays.sort(int[] a, int fromIndex, int toIndex)
public static void sort(T[] a,int fromIndex,int toIndex, Comparator c)
2.1.2 并行排序
主要是调用静态方法 parallelSort() ,支持基本数据类型数组,引用类型的数组需要实现Comparable接口,或者调用方法时传入指定的比较器。
这种排序方式,会去判断当前数组的大小是否 小于最小的并行排序长度MIN_ARRAY_SORT_GRAN,或者并行池的数量为1,如果满足条件,还会调用Dual-Pivot Quicksort(双轴快排)方法来排序,否则才去执行并行排序。调用参数与sort一致。
2.2 查找相关
主要是调用静态方法 binarySearch() ,支持基本数据类型数组,引用类型的数组需要实现Comparable接口,或者调用方法时传入指定的比较器。查找算法使用的是二分查找,除此之外,数组一定要是排过序的,不然二分查找无法实行。
public static int binarySearch(long[] a, long key)
public static int binarySearch(long[] a, int fromIndex, int toIndex, long key)
2.3 比较相关
2.3.1 普通比较
Arrays.equals(),比较数组是否相等,支持所有数据类型,其中引用类型会调用equals方法,如果没有重写,则比较的是地址值。
public static boolean equals(long[] a, long[] a2)
public static boolean equals(long[] a, int aFromIndex, int aToIndex, long[] b, int bFromIndex, int bToIndex)
2.3.2 深度比较
Arrays.deepEquals(),针对引用类型,会比较该对象里的所有基本数据类型,如果全部相等,才对比成功。
public static boolean deepEquals(Object[] a1, Object[] a2)
2.3.3 compare比较
返回第一个不相等的元素的差值,如果两个数组完全相等,返回0,如果一个数组a比另一个数组b长度短,但是b中的数据与a完全相同直到a没有数据,此时返回a b的数组长度的差值。
public static int compare(boolean[] a, boolean[] b)
public static int compare(boolean[] a, int aFromIndex, int aToIndex, boolean[] b, int bFromIndex, int bToIndex)
2.3.4 compareUnsigned比较
compare的无符号版
2.3.5 mismatch比较
返回第一个不相同的下标,如果相同就返回-1
public static int mismatch(int[] a, int[] b)
public static int mismatch(int[] a, int aFromIndex, int aToIndex, int[] b, int bFromIndex, int bToIndex)
2.4 打印相关
2.4.1 普通打印
Arrays.toString,将数组打印出来。
2.4.2 深度打印
Arrays.deepToString,针对引用类型,会把该对象里的所有基本数据类型打印出来。
2.5 计算hashCode
2.5.1 普通计算
Arrays.hashCod,支持所有数据类型,其中引用类型会调用 hashCode 方法。
public static int hashCode(int[] a)
2.5.2 深度计算
Arrays.deepHashCode,针对引用类型,会计算该对象里的所有基本数据类型的hashCode。
public static int deepHashCode(Object[] a)
2.6 拷贝相关
Arrays.copyOf
得到一个新的数组,在复制了original数组中的元素之后,长度还变为newLength。如果长度变长,则填充默认数据。如果长度变短,多的数据就没了
public static int[] copyOf(int[] original, int newLength)
Arrays.copyOfRange
返回一个数组,并且拥有给定数组的指定范围的数据。
public static int[] copyOfRange(int[] original, int from, int to)
其中 copyOf 和 copyOfRange 都会调用 System的一个静态方法 arraycopy。
2.7 赋值相关
Arrays.fill,可以为一个数组赋上初始值。
public static void fill(int[] a, int val)
public static void fill(int[] a, int fromIndex, int toIndex, int val)
2.8 转换为集合List
Arrays.asList,将一个数组转换成一个List。需要注意的是 该List是 Arrays的一个内部类,并不是我们常用的 ArrayList。
public static <T> List<T> asList(T... a)
2.9 转换为stream
首先对于stream,它是一种高级迭代器,可以为他执行一些操作。这个Stream方法就是把数组中的数据或者指定范围的数据放入流中。注意stream终端操作后就不能再使用了。
public static IntStream stream(int[] array)
public static IntStream stream(int[] array, int startInclusive, int endExclusive)
八、泛型与数组
java中数组是不支持泛型的。
由于泛型只是在编译的时候,起到类型检测,及类型转换字节码的生成,也就是说具有泛型的java文件,最终生成的字节码会将泛型信息抹去,具体数据的引用类型一般都用object的来替代。并在对应的位置加上了类型转换代码。
而java中规定数组在实例化的时候,需要确切的知道存放数据的类型(这样更方便的操作使用数组)。也就是说假设数组支持泛型,那么在编译成字节码的时候对于T[] = new T[10];最终会编译成Object[] objects=new Object[10],也就是说数组的具体类型在运行期间为object 类型,这个时候我们可以将任何类型的对象存储到数组中,因为object是所有对象的父类。最后因为泛型会进行类型转换,如果存储的对象类型有问题,就会抛出转换异常。