一、jdk原生Arrays分析(版本1.8.0)
1.1 引入
Arrays是jdk原生对数组操作的工具类,相信在项目中经常可以看到Arrays.sort , Arrays.binarySearch,Arrays.fill等方法。但是没有对Arrays的源码进行进一步了解,为了让自己有对Arrays有更深的了解,所以写这篇文章介绍我对Arrays源码的分析。
1.2 源码解析
1.2.1 构造器
// Arrays是工具类,没有必要创建对应,推荐在工具类中都加上这样的代码
private Arrays() {}
1.2.2 主要方法
Arrays方法中有很多重载方法,为了避免重复,取其中具有代表性的方法进行讲解
1.2.2.1 rangeCheck
/**
* @param arrayLength 数组自身长度
* @param fromIndex 起始索引位置
* @param toIndex 结束索引位置
* 注意如果校验不成功直接抛出异常
*/
private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException(
"fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
}
if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
}
if (toIndex > arrayLength) {
throw new ArrayIndexOutOfBoundsException(toIndex);
}
}
1.2.2.2 sort
public static void sort(double[] a, int fromIndex, int toIndex) {
// 校验(前面已经介绍了)
rangeCheck(a.length, fromIndex, toIndex);
// 双轴快速排序(会重新写一篇文章介绍这个算法)
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
}
1.2.2.3 parallelSort
public static void parallelSort(double[] a) {
int n = a.length, p, g;
if (n <= MIN_ARRAY_SORT_GRAN ||
// commonPoolParallelism : 取决于可用内核的数量
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
else
//当数组长度大于 8192 时使用并行排序
new ArraysParallelSortHelpers.FJDouble.Sorter
(null, a, new double[n], 0, n, 0,
((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
MIN_ARRAY_SORT_GRAN : g).invoke();
}
2.2.4 binarySearch
// 二分查找
public static int binarySearch(double[] a, int fromIndex, int toIndex,
double key) {
rangeCheck(a.length, fromIndex, toIndex);
// 主要方法
return binarySearch0(a, fromIndex, toIndex, key);
}
/**
* @param a 数组(需要已经排序)
* @param fromIndex 数组起始索引(包含)
* @param toIndex 数组结束索引(不包含)
* @param key 查找数字
*/
private static int binarySearch0(double[] a, int fromIndex, int toIndex,double key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
double midVal = a[mid]; // 中间值
if (midVal < key)
low = mid + 1; // 如果中间值小于需要查找的值,说明已经从中间索引的后位开始查找
else if (midVal > key)
high = mid - 1; // 如果中间值大于需要查找的值,说明已经从中间索引的前位开始查找
else {
// double类型或者float类型的数据不能直接通过==,进行比较
// 将double类型的值转化为long类型的数据比较
long midBits = Double.doubleToLongBits(midVal);
long keyBits = Double.doubleToLongBits(key);
if (midBits == keyBits)
return mid;
else if (midBits < keyBits)
low = mid + 1;
else
high = mid - 1;
}
}
// 如果找不到返回负数
return -(low + 1);
}
1.2.2.5 fill
/**
* 将数组的某一部分填充为固定值
*/
public static void fill(double[] a, int fromIndex, int toIndex,double val){
rangeCheck(a.length, fromIndex, toIndex);
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
2.2.6 copyOf
/**
* 数组拷贝
* @param original 需要拷贝的数组
* @param newLength 需要拷贝的长度
* @param newType 拷贝之后的数组类型
*/
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
// Array.newInstance根据数组元素类型和长度创建数组对象
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
// 拷贝数组
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
二、ArrayUtils(common-lang3)
2.1 数组转换为Map集合
/**
* 将数组转换为Map
*/
public static Map<Object, Object> toMap(Object[] array) {
if (array == null) {
return null;
} else {
// hashmap默认的装载因子为0.75,如果设置和array长度一样,就会触发一次扩容
Map<Object, Object> map = new HashMap((int)((double)array.length * 1.5D));
for(int i = 0; i < array.length; ++i) {
Object object = array[i];
// 如果每个元素就是Entry,直接添加到map中
if (object instanceof Entry) {
Entry<?, ?> entry = (Entry)object;
map.put(entry.getKey(), entry.getValue());
} else {
if (!(object instanceof Object[])) {
throw new IllegalArgumentException("Array element " + i + ", '" + object + "', is neither of type Map.Entry nor an Array");
}
Object[] entry = (Object[])((Object[])object);
if (entry.length < 2) {
throw new IllegalArgumentException("Array element " + i + ", '" + object + "', has a length less than 2");
}
// 取每个子数组中的前两位
map.put(entry[0], entry[1]);
}
}
return map;
}
}
2.2 子数组
/**
* 获取子数组
* @param array 原数组
* @param startIndexInclusive 起始索引位置
* @param endIndexExclusive 结束索引位置
*/
public static <T> T[] subarray(T[] array, int startIndexInclusive, int endIndexExclusive) {
if (array == null) {
return null;
} else {
// 修复索引
if (startIndexInclusive < 0) {
startIndexInclusive = 0;
}
if (endIndexExclusive > array.length) {
endIndexExclusive = array.length;
}
int newSize = endIndexExclusive - startIndexInclusive;
// 元素类型
Class<?> type = array.getClass().getComponentType();
Object[] subarray;
if (newSize <= 0) {
subarray = (Object[])((Object[])Array.newInstance(type, 0));
return subarray;
} else {
// 创建指定大小的数组
subarray = (Object[])((Object[])Array.newInstance(type, newSize));
System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
return subarray;
}
}
}
2.3 数组反转
/**
* 数组反转
* @param array 数组
* @param startIndexInclusive 起始索引
* @param endIndexExclusive 结束索引
*/
public static void reverse(Object[] array, int startIndexInclusive, int endIndexExclusive) {
if (array != null) {
// 修复索引
int i = startIndexInclusive < 0 ? 0 : startIndexInclusive;
for(int j = Math.min(array.length, endIndexExclusive) - 1; j > i; ++i) {
// 交换数据
Object tmp = array[j];
array[j] = array[i];
array[i] = tmp;
--j;
}
}
}
4 数组下标位置
/**
* 数组元素下标位置
* @param array 需要查找的数组
* @param objectToFind 查找元素
* @param startIndex 起始索引
* @return 没有找到返回-1
*/
public static int indexOf(Object[] array, Object objectToFind, int startIndex) {
if (array == null) {
return -1;
} else {
// 起始索引
if (startIndex < 0) {
startIndex = 0;
}
int i;
// 考虑null
if (objectToFind == null) {
for(i = startIndex; i < array.length; ++i) {
if (array[i] == null) {
return i;
}
}
} else {
// 遍历查找
for(i = startIndex; i < array.length; ++i) {
if (objectToFind.equals(array[i])) {
return i;
}
}
}
return -1;
}
}
2.5 合并数组
/**
* 数组合并
*
*/
public static <T> T[] addAll(T[] array1, T... array2) {
// 返回拷贝的数组
if (array1 == null) {
return clone(array2);
} else if (array2 == null) {
return clone(array1);
} else {
Class<?> type1 = array1.getClass().getComponentType();
// 创建两个数组长度和的数组
T[] joinedArray = (Object[])((Object[])Array.newInstance(type1, array1.length + array2.length));
System.arraycopy(array1, 0, joinedArray, 0, array1.length);
try {
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
return joinedArray;
} catch (ArrayStoreException var6) {
Class<?> type2 = array2.getClass().getComponentType();
// Class.isAssignableFrom()是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的子类或接口。
if (!type1.isAssignableFrom(type2)) {
throw new IllegalArgumentException("Cannot store " + type2.getName() + " in an array of " + type1.getName(), var6);
} else {
throw var6;
}
}
}
}
三、自我扩展
3.1.将两个数组转换为Map集合
/**
* 将两个数组转换为Map
*
* @return
*/
private static final Map EMPTY_MAP= new HashMap(0);
public static <T, U> Map<T, U> toMap(T[] arr1, U[] arr2) {
if (arr1 == null || arr2 == null) {
return null;
}
if (arr1.length != arr2.length) {
throw new IllegalArgumentException(
"arr1'length is not equals to arr2'length");
}
int len = arr1.length;
if (0 == len) {
return EMPTY_MAP;
}
Map<T, U> result = new HashMap<T, U>((int) (len * 1.5));
for (int i = 0; i < len; i++) {
result.put(arr1[i], arr2[i]);
}
return result;
}
```