Arrays 类包含用于操作数组的各种方法,比如:排序、查找、填充、拷贝、相等判断等。
排序
Arrays.sort() 入参支持各种基本类型的数组,也支持自定义类型的数组,使用了双轴快速排序算法
下面 demo 为自定义类型的数组排序:
@Testpublic void test16() {// ImmutableList 是 Guava 框架中的类ImmutableList<SortDTO> list = ImmutableList.of(new SortDTO(500),new SortDTO(100),new SortDTO(400),new SortDTO(200));SortDTO[] array = new SortDTO[list.size()];list.toArray(array);Arrays.sort(array, new Comparator<SortDTO>() {@Overridepublic int compare(SortDTO o1, SortDTO o2) {// 当方法的返回值大于 0 时,就将数组的前一个数和后一个数做交换。// 升序的话就o1 - o2// 降序的话就o2 - o1return o1.getSortTarget() - o2.getSortTarget();}});System.out.println(Arrays.toString(array));}
public class SortDTO {private Integer sortTarget;public Integer getSortTarget() {return sortTarget;}public SortDTO(Integer sortTarget) {this.sortTarget = sortTarget;}@Overridepublic String toString() {return "SortDTO{" +"sortTarget=" + sortTarget +'}';}}
查找
Arrays.binarySearch() 用于快速从数组中查找出对应的值。
返回参数对应数组下标的值,如果查询不到,则返回负数。
如果被搜索的数组是无序的,一定要先排序,否则二分搜索很有可能搜索不到binarySearch() 的底层源码实现如下:
private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,T key, Comparator<? super T> c) {// 比较器 c 为空,直接使用 key 的 Comparable.compareToif (c == null) {// 使用内部排序器进行比较的方法return binarySearch0(a, fromIndex, toIndex, key);}int low = fromIndex;int high = toIndex - 1;// 开始位置小于结束位置,就会一直循环搜索while (low <= high) {int mid = (low + high) >>> 1;T midVal = a[mid];// 数组中间值和给定值大小比较int cmp = c.compare(midVal, key);// cmp < 0,代表中间值小于给定值if (cmp < 0) {low = mid + 1;} else if (cmp > 0) {high = mid - 1;} else {// 找到了return mid;}}// 返回值是负数,代表没有找到return -(low + 1);}
拷贝
数组拷贝,有时需要拷贝整个数组,有时需要拷贝部分,比如 ArrayList 在 add(扩容)或 remove(删除元素不是最后一个)操作时,会进行一些拷贝。
拷贝整个数组可以使用 copyOf(),拷贝部分可以使用 copyOfRange()。copyOfRange() 的底层源码实现如下:
// 注意:拷贝的数组区间是左闭右开的public static char[] copyOfRange(char[] original, int from, int to) {// 需要拷贝的长度int newLength = to - from;if (newLength < 0)throw new IllegalArgumentException(from + " > " + to);// 初始化新数组(拷贝的目标数组)char[] copy = new char[newLength];// 调用 native 方法进行拷贝System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength));return copy;}
相等判断
Arrays.equals() 用于:比较一维数组,入参数组类型包括了八大基础数据和引用数据类型,入参为引用数据类型时,调用 object.equals() 进行元素的比较。Arrays.deepEquals() 的入参只支持 Object[],用于:比较引用数据的多维数组的各元素是否相等,调用了 object.equals() 进行各元素的比较。
以 Object[] 为例说明 equals() 的底层代码实现
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];if (!(o1==null ? o2==null : o1.equals(o2)))return false;}return true;}
deepEquals() 的底层源码实现如下:
public static boolean deepEquals(Object[] a1, Object[] a2) {if (a1 == a2)return true;if (a1 == null || a2==null)return false;int length = a1.length;if (a2.length != length)return false;for (int i = 0; i < length; i++) {Object e1 = a1[i];Object e2 = a2[i];if (e1 == e2)continue;if (e1 == null)return false;// Figure out whether the two elements are equal// 判断这两个元素是否相等boolean eq = deepEquals0(e1, e2);if (!eq)return false;}return true;}
static boolean deepEquals0(Object e1, Object e2) {assert e1 != null;boolean eq;if (e1 instanceof Object[] && e2 instanceof Object[])eq = deepEquals ((Object[]) e1, (Object[]) e2);else if (e1 instanceof byte[] && e2 instanceof byte[])eq = equals((byte[]) e1, (byte[]) e2);else if (e1 instanceof short[] && e2 instanceof short[])eq = equals((short[]) e1, (short[]) e2);else if (e1 instanceof int[] && e2 instanceof int[])eq = equals((int[]) e1, (int[]) e2);else if (e1 instanceof long[] && e2 instanceof long[])eq = equals((long[]) e1, (long[]) e2);else if (e1 instanceof char[] && e2 instanceof char[])eq = equals((char[]) e1, (char[]) e2);else if (e1 instanceof float[] && e2 instanceof float[])eq = equals((float[]) e1, (float[]) e2);else if (e1 instanceof double[] && e2 instanceof double[])eq = equals((double[]) e1, (double[]) e2);else if (e1 instanceof boolean[] && e2 instanceof boolean[])eq = equals((boolean[]) e1, (boolean[]) e2);elseeq = e1.equals(e2);return eq;}
数组->集合
把数组转化成集合时,常使用 Arrays.asList(array),这个方法有两个坑
- 数组被修改后,会直接影响到集合
- 不能对集合进行 add、remove 等操作,否则运行时会报 UnsupportedOperationExceptio
以下 demo 用于演示这两个坑:
@Testpublic void test18() {Integer[] array = new Integer[]{1, 2, 3, 4, 5, 6};List<Integer> list = Arrays.asList(array);// 打印结果为:1System.out.println(list.get(0));array[0] = 10;// 打印结果为:10System.out.println(list.get(0));// 抛出 java.lang.UnsupportedOperationExceptionlist.add(7);}
Arrays.asList 方法返回的 List 并不是 java.util.ArrayList,而是自己内部的一个静态类,该静态类直接持有数组的引用,并且没有实现 add、remove 等方法,这就是坑的原因。asList() 的底层源码实现如下:
public static <T> List<T> asList(T... a) {// 此处 new 的 ArrayList,并不是 java.util.ArrayList// 而是自己内部的静态类return new ArrayList<>(a);}private static class ArrayList<E> extends AbstractList<E>implements RandomAccess, java.io.Serializable {private static final long serialVersionUID = -2764017481108945198L;// 这里的数组直接指向转化的数组private final E[] a;ArrayList(E[] array) {a = Objects.requireNonNull(array);}@Overridepublic int size() {return a.length;}@Overridepublic Object[] toArray() {return a.clone();}@Override@SuppressWarnings("unchecked")public <T> T[] toArray(T[] a) {int size = size();if (a.length < size)return Arrays.copyOf(this.a, size,(Class<? extends T[]>) a.getClass());System.arraycopy(this.a, 0, a, 0, size);if (a.length > size)a[size] = null;return a;}@Overridepublic E get(int index) {return a[index];}@Overridepublic E set(int index, E element) {E oldValue = a[index];a[index] = element;return oldValue;}@Overridepublic int indexOf(Object o) {E[] a = this.a;if (o == null) {for (int i = 0; i < a.length; i++)if (a[i] == null)return i;} else {for (int i = 0; i < a.length; i++)if (o.equals(a[i]))return i;}return -1;}@Overridepublic boolean contains(Object o) {return indexOf(o) != -1;}@Overridepublic Spliterator<E> spliterator() {return Spliterators.spliterator(a, Spliterator.ORDERED);}@Overridepublic void forEach(Consumer<? super E> action) {Objects.requireNonNull(action);for (E e : a) {action.accept(e);}}@Overridepublic void replaceAll(UnaryOperator<E> operator) {Objects.requireNonNull(operator);E[] a = this.a;for (int i = 0; i < a.length; i++) {a[i] = operator.apply(a[i]);}}@Overridepublic void sort(Comparator<? super E> c) {Arrays.sort(a, c);}}
