JDK1.8源码(四)——java.util.Arrays类
一、概述
1、介绍
Arrays 类是 JDK1.2 提供的一个工具类,提供处理数组的各种方法,基本上都是静态方法,能直接通过类名Arrays调用。
二、类源码
1、asList()方法
将一个泛型数组转化为List集合返回。但是,这个List集合既不是ArrayList实例,也不是Vector实例。它是一个固定长度的 List 集合,是 Arrays 的一个内部类 java.util.Arrays.ArrayList。
代码示例:使用
public class Main { public static void main(String[] args) throws Exception { Integer[] d = {3, 1, 2}; final List<Integer> integers = Arrays.asList(d); System.out.println(integers); } } // 结果 [3, 1, 2]
源码示例:
public static <T> List<T> asList(T... a) { return new ArrayList<>(a); } private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { // 源码省略,读者可自行用idea查看 }
说明:
①、定长列表,只能对其进行查看或者修改,不能进行添加或者删除操作
public class Main { public static void main(String[] args) { String[] str = {"a", "b", "c"}; List<String> list = Arrays.asList(str); // 可以进行修改 list.set(1, "e"); System.out.println(list.toString()); // [a, e, c] list.add("a"); //添加元素会报错 java.lang.UnsupportedOperationException } }
查看源码发现,该类没有add() 和 remove()方法。如果对其进行增加或者删除操作,会调用其父类 AbstractList 对应的方法,而追溯父类的方法最终会抛出 UnsupportedOperationException 异常。源码如下:
// 类 AbstractList public boolean add(E e) { add(size(), e); return true; } public void add(int index, E element) { throw new UnsupportedOperationException(); }
②、引用类型的数组和基本类型的数组区别
public class Main { public static void main(String[] args) { String[] str = {"a", "b", "c"}; final List<String> list = Arrays.asList(str); System.out.println(list.size()); // 3 int[] i = {1, 2, 3}; final List<int[]> ints = Arrays.asList(i); System.out.println(ints.size()); // 1 Integer[] in = {1, 2, 3}; final List<Integer> integers = Arrays.asList(in); System.out.println(integers.size()); // 3 } }
类类型才是泛型,基本数据类型不能作为泛型的参数。读者根据上面结果自行体会一下。
③、返回的是原数组的里的引用,不是独立出来的集合对象
public class Main { public static void main(String[] args) { String[] str = {"a", "b", "c"}; List<String> listStr = Arrays.asList(str); System.out.println(Arrays.toString(str)); // [a, b, c] listStr.set(0, "d"); System.out.println(Arrays.toString(str)); // [d, b, c] } }
这里,修改的是返回的集合的内容,但是原数组的内容也变化了,所以只是返回了原数组的一个视图。如果希望返回一个全新的集合,可以如下:
public class Main { public static void main(String[] args) { String[] str = {"a", "b", "c"}; ArrayList<String> strings = new ArrayList<>(Arrays.asList(str)); strings.add("d"); System.out.println(Arrays.toString(str)); // [a, b, c] System.out.println(strings); // [a, b, c, d] } }
2、sort()方法
用于数组排序,有一系列重载方法。注意,如果是 Object 类型,需要实现Comparable接口或者传入一个比较器 Comparator ,使其具有可比性。可以参考这篇。Java比较器。
源码示例:
public static void sort(int[] a) { DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); }
这个方法的源码很长,分别对数组的长度进行了各种算法的划分,包括快速排序,插入排序,冒泡排序都有使用。详细源码可以参考这篇博客。
3、binarySearch()方法
用于数组查找,是基于二分查找算法实现,有一系列重载方法,适用于各种基本数据类型以及对象数组。
值得注意的是:调用此方法,要求待查找的数组有序。存在,返回元素下标;不存在,返回一个负数(不是 -1)。
源码示例:
public static int binarySearch(int[] a, int key) { return binarySearch0(a, 0, a.length, key); } // 典型的二分查找算法 private static int binarySearch0(int[] a, int fromIndex, int toIndex, int key) { int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1; int midVal = a[mid]; if (midVal < key) low = mid + 1; else if (midVal > key) high = mid - 1; else return mid; // key found } // 找不到,返回并不是 -1 return -(low + 1); // key not found. }
4、copyOf()方法
拷贝数组元素。底层采用 System.arraycopy() 实现,这是一个native方法。
注意:这个方法在ArrayList源码扩容时,也是用的它。
代码示例:
public class Main { public static void main(String[] args) { int[] old = {1, 3, 2}; int[] ints = Arrays.copyOf(old, 5); System.out.println(Arrays.toString(ints)); // [1, 3, 2, 0, 0] int[] ints1 = Arrays.copyOf(old, 1); System.out.println(Arrays.toString(ints1)); // [1] } }
源码示例:
// Arrays类 public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, // 长度是旧数组长度 与 新长度 取小 Math.min(original.length, newLength)); return copy; } // System类 public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
src:源数组
srcPos:源数组要复制的起始位置
dest:目的数组
destPos:目的数组放置的起始位置
length:复制的长度
注意:src 和 dest都必须是同类型或者可以进行转换类型的数组。
5、equals()/deepEquals()方法
①、equals
用于比较两个数组中对应位置的每一个元素是否相等。
源码示例:
// 基本数据类型数组比较 public static boolean equals(int[] a, int[] a2) { // 引用相等,则相同 if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; // 长度不同,则不相同 if (a2.length != length) return false; // 循环依次比较数组中每个元素是否相等 for (int i=0; i<length; i++) if (a[i] != a2[i]) return false; return true; } // 引用类型数组比较 public static boolean equals(Object[] a, Object[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) { Object o1 = a[i]; Object o2 = a2[i]; // 对象相同通过 equals 方法判断 if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return true; }
②、deepEquals
比较两个数组的元素是否相等,可以嵌套任意层次的数组。
源码就是递归的使用 deepEquals 判断每一层的数组是否相同。
代码示例:
public class Main { public static void main(String[] args) { String[][] name1 = {{"G", "a", "o"}, {"H", "u", "a", "n"}, {"j", "i", "e"}}; String[][] name2 = {{"G", "a", "o"}, {"H", "u", "a", "n"}, {"j", "i", "e"}}; System.out.println(Arrays.equals(name1, name2));// false System.out.println(Arrays.deepEquals(name1, name2));// true } }
6、fill()方法
该系列方法用于给数组赋值,并能指定某个范围赋值。
代码示例:
public class Main { public static void main(String[] args) { int[] arr = new int[4]; System.out.println(Arrays.toString(arr)); // [0, 0, 0, 0] Arrays.fill(arr, 6); System.out.println(Arrays.toString(arr)); // [6, 6, 6, 6] } }
源码示例:
// 不写注释也能看懂的代码 public static void fill(int[] a, int val) { for (int i = 0, len = a.length; i < len; i++) a[i] = val; } public static void fill(int[] a, int fromIndex, int toIndex, int val) { rangeCheck(a.length, fromIndex, toIndex); for (int i = fromIndex; i < toIndex; i++) a[i] = val; }
7、toString 和 deepToString方法
toString 用来打印一维数组的元素,而 deepToString 用来打印多层次嵌套的数组元素。
参考文档:https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
- 【JUC】JDK1.8源码分析之CyclicBarrier(四)
- 【jdk1.8】Integer源码分析
- (转载)Java中HashMap底层实现原理(JDK1.8)源码分析
- JDK1.8源码学习之HashSet.java
- java HashMap源码分析(JDK1.8)
- Java Jdk1.8 HashMap源码阅读笔记一
- JDK1.8源码解析之ConcurrentHashMap
- HashMap源码之hash()函数分析(JDK 1.8)
- jdk1.8 J.U.C并发源码阅读------CyclicBarrier源码解析
- HashMap源码分析 JDK1.8
- jdk1.8 AtomicInteger以及AtomicStampedReference源码分析
- HashMap源码探讨(基于JDK1.8)
- 【jdk1.8】PriorityQueue源码分析
- Java中HashMap底层实现原理(JDK1.8)源码分析
- [Java]JDK1.8 ArrayList源码剖析(二)
- HashMap源码解析(JDK1.8)
- JDK1.8源码中的编程习惯
- 源码分析系列1:HashMap源码分析(基于JDK1.8)
- 【JDK1.8源码剖析】Collection接口
- Java集合源码实现一:ArrayList(jdk1.8)