Arrays 类包含用于操作数组的各种方法,比如:排序、查找、填充、拷贝、相等判断等。
排序
Arrays.sort() 入参支持各种基本类型的数组,也支持自定义类型的数组,使用了双轴快速排序算法
下面 demo 为自定义类型的数组排序:
@Test
public 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>() {
@Override
public int compare(SortDTO o1, SortDTO o2) {
// 当方法的返回值大于 0 时,就将数组的前一个数和后一个数做交换。
// 升序的话就o1 - o2
// 降序的话就o2 - o1
return 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;
}
@Override
public 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.compareTo
if (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);
else
eq = e1.equals(e2);
return eq;
}
数组->集合
把数组转化成集合时,常使用 Arrays.asList(array),这个方法有两个坑
- 数组被修改后,会直接影响到集合
- 不能对集合进行 add、remove 等操作,否则运行时会报 UnsupportedOperationExceptio
以下 demo 用于演示这两个坑:
@Test
public void test18() {
Integer[] array = new Integer[]{1, 2, 3, 4, 5, 6};
List<Integer> list = Arrays.asList(array);
// 打印结果为:1
System.out.println(list.get(0));
array[0] = 10;
// 打印结果为:10
System.out.println(list.get(0));
// 抛出 java.lang.UnsupportedOperationException
list.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);
}
@Override
public int size() {
return a.length;
}
@Override
public 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;
}
@Override
public E get(int index) {
return a[index];
}
@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
@Override
public 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;
}
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}
@Override
public 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]);
}
}
@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}