工具类通用特征写法:
尽量不在工具方法中,对共享变量有做修改的操作访问(如果必须要做的话,必须加锁),因为会有线程安全的问题。除此之外,工具类方法本身是没有线程安全问题的,可以放心使用。
Arrays.sort 方法使用了双轴快速排序算法
Arrays.binarySearch 方法主要用于快速从数组中查找出对应的值。其支持的入参类型非常多,如 byte、int、long 各种类型的数组。返回参数是查找到的对应数组下标的值,如果查询不到,则返回负数。
对于二分查找的代码来说
二分法底层代码
// a:我们要搜索的数组,fromIndex:从那里开始搜索,默认是0; toIndex:搜索到何时停止,默认是数组大小 // key:我们需要搜索的值 c:外部比较器 private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c) { // 如果比较器 c 是空的,直接使用 key 的 Comparable.compareTo 方法进行排序 // 假设 key 类型是 String 类型,String 默认实现了 Comparable 接口,就可以直接使用 compareTo 方法进行排序 if (c == null) { // 这是另外一个方法,使用内部排序器进行比较的方法 return binarySearch0(a, fromIndex, toIndex, key); } int low = fromIndex; int high = toIndex - 1; // 开始位置小于结束位置,就会一直循环搜索 while (low <= high) { // 假设 low =0,high =10,那么 mid 就是 5,所以说二分的意思主要在这里,每次都是计算索引的中间值 int mid = (low + high) >>> 1; T midVal = a[mid]; // 比较数组中间值和给定的值的大小关系 int cmp = c.compare(midVal, key); // 如果数组中间值小于给定的值,说明我们要找的值在中间值的右边 if (cmp < 0) low = mid + 1; // 我们要找的值在中间值的左边 else if (cmp > 0) high = mid - 1; else // 找到了 return mid; // key found } // 返回的值是负数,表示没有找到 return -(low + 1); // key not found. }
数组拷贝我们经常遇到,有时需要拷贝整个数组,有时需要拷贝部分,比如 ArrayList 在 add(扩容) 或 remove(删除元素不是最后一个) 操作时,会进行一些拷贝。拷贝整个数组我们可以使用 copyOf 方法,拷贝部分我们可以使用 copyOfRange 方法
copyOfRange底层源码:
// original 原始数组数据 // from 拷贝起点 // to 拷贝终点 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 的拷贝方法,实际上底层调用的是 System.arraycopy 这个 native 方法
Collections 也提供了 sort 和 binarySearch 方法,sort 底层使用的就是 Arrays.sort 方法,binarySearch 底层是自己重写了二分查找算法,实现的逻辑和 Arrays 的二分查找算法完全一致,这两个方法上 Collections 和 Arrays 的内部实现很类似。
以 max 方法为例,max 提供了两种类型的方法,一个需要传外部排序器,一个不需要传排序器,但需要集合中的元素强制实现 Comparable 接口,后者的泛型定义很有意思。
max 方法泛型 T 定义得非常巧妙,意思是泛型必须继承 Object 并且实现 Comparable 的接口。一般让我们来定义的话,我们可以会在方法里面去判断有无实现 Comparable 的接口,这种是在运行时才能知道结果。而这里泛型直接定义了必须实现 Comparable 接口,在编译的时候就可告诉使用者,当前类没有实现 Comparable 接口,使用起来很友好。
对于线程安全的集合方法都是 synchronized
开头的,从方法名可以看出来底层是通 synchronized 轻量锁来实现的。
对于不可变的集合都是以 unmodifiable
开头的,这类方法的意思是,我们会从原集合中,得到一个不可变的新集合,新集合只能访问,无法修改;一旦修改,就会抛出异常。这主要是因为只开放了查询方法,其余任何修改操作都会抛出异常。
equals 和 deepEquals,前者是判断基本类型和自定义类的,后者是用来判断数组的
isNull 和 nonNull 对于对象是否为空返回 Boolean 值,requireNonNull 方法更加严格,如果一旦为空,会直接抛出异常,需要根据生活的场景选择使用。