org.apache.commons.lang3.ArrayUtils源码分析
来源:互联网 发布:在哪里买正版windows 编辑:程序博客网 时间:2024/06/05 04:47
这个类竟然有8000多行,太不科学了,不过分析得知大量代码是重复的,换一下类型(8大基本类型,除部分代码外,全部重复,因此下面的示例代码只给出int类型的实现及object类型的实现)
属性
- 各种类型的空数组,包括空对象数组,空类数组,空字符串数组,8大基本类型数组,8大基本类封装类数组,这些数组的命名规则为
EMPTY_XXX_ARRAY
,其中,XXX的含义为:对象(OBJECT
),类(CLASS
),基本类型(BYTE、CHAR、SHORT、INT、LONG、FLOAT、DOUBLE、BOOLEAN
),基本类型封装类型(BYTE_OBJECT、CHARACTER_OBJECT、SHORT_OBJECT、INTEGER_OBJECT、LONG_OBJECT、FLOAT_OBJECT、DOUBLE_OBJECT、BOOLEAN_OBJECT
)
示例如下:
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0]public static final String[] EMPTY_STRING_ARRAY = new String[0]public static final long[] EMPTY_LONG_ARRAY = new long[0]public static final Long[] EMPTY_LONG_OBJECT_ARRAY = new Long[0]
- 用于指示一个元素不在数组中的标志,
INDEX_NOT_FOUND
:
public static final int INDEX_NOT_FOUND = -1;
构造方法
该方法用于javaBean,用户不应该创建ArrayUtils实例,因为ArrayUtils的方法都是静态的
public ArrayUtils() { super();}
相关方法
toString方法
- toString(final Object array),当数组为null时,返回”{}”
//核心代码return toString(array, "{}");
- toString(final Object array, final String stringIfNull),调用ToStringBuilder实现
//核心代码if (array == null) { return stringIfNull;}return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
hashCode方法
- hashCode(final Object array),调用HashCodeBuilder实现
//核心代码return new HashCodeBuilder().append(array).toHashCode();
toMap方法
- Map<Object, Object> toMap(final Object[] array),接受两种array元素类型:
- Map.Entry<?, ?>
- Object[],元素个数要大于等于2,只取第一第二个元素,第一个作为key,第二个作为value
//核心代码final Map<Object, Object> map = new HashMap<>((int) (array.length * 1.5));for (int i = 0; i < array.length; i++) { final Object object = array[i]; if (object instanceof Map.Entry<?, ?>) { final Map.Entry<?,?> entry = (Map.Entry<?,?>) object; map.put(entry.getKey(), entry.getValue()); } else if (object instanceof Object[]) { final Object[] entry = (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]); } else { throw new IllegalArgumentException("Array element " + i + ", '" + object + "', is neither of type Map.Entry nor an Array"); }}return map;
toArray方法
- toArray(final T… items),将输入的参数转换成数组
clone方法
调用array的clone方法实现,有判空操作
//核心代码return array == null ? null : array.clone();
nullToEmpty方法
- nullToEmpty(final T[] array, final Class
//核心代码if (array == null) { return type.cast(Array.newInstance(type.getComponentType(), 0));}return array;
- nullToEmpty(final T[] array),将null或长度为0的array转换成同类型的空数组对象,若传入的array对象非空,则原样返回
//核心代码return isEmpty(array) ? EMPTY_OBJECT_ARRAY : array;
subarray方法
- 核心是调用System.arraycopy方法,startIndexInclusive小于0则从0开始,endIndexExclusive大于array.length,则到array.length截止
//核心代码final int newSize = endIndexExclusive - startIndexInclusive;final Class<?> type = array.getClass().getComponentType();if (newSize <= 0) { @SuppressWarnings("unchecked") // OK, because array is of type T final T[] emptyArray = (T[]) Array.newInstance(type, 0); return emptyArray;}@SuppressWarnings("unchecked") // OK, because array is of type TfinalT[] subarray = (T[]) Array.newInstance(type, newSize);System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);return subarray;
isSameLength方法
判断两个数组长度是否相同
//核心代码return getLength(array1) == getLength(array2);public static int getLength(final Object array) { return array == null ? 0 : Array.getLength(array);}
isSameType方法
public static boolean isSameType(final Object array1, final Object array2) { if (array1 == null || array2 == null) { throw new IllegalArgumentException("The Array must not be null"); } return array1.getClass().getName().equals(array2.getClass().getName());}
reverse方法
- 核心方法是交换第i个元素与第lastIndex-i个元素
public static void reverse(final Object[] array) { if (array == null) { return; } reverse(array, 0, array.length);}public static void reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) { if (array == null) { return; } int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; int j = Math.min(array.length, endIndexExclusive) - 1; boolean tmp; while (j > i) { tmp = array[j]; array[j] = array[i]; array[i] = tmp; j--; i++; }}
swap方法
- 交换两个元素值的位置
public static void swap(final Object[] array, final int offset1, final int offset2) { if (array == null || array.length == 0) { return; } swap(array, offset1, offset2, 1);}//交换从offset1开始的len个元素与offset2开始的len个元素len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);for (int i = 0; i < len; i++, offset1++, offset2++) { final boolean aux = array[offset1]; array[offset1] = array[offset2]; array[offset2] = aux;}
shift方法
- 在子数组范围内向右循环移动n个元素,其实现是调用swap方法,比旋转左边len-n个子元素,再旋转右边n个元素,最后再旋转所有len个元素慢3倍
public static void shift(final Object[] array, final int offset) { if (array == null) { return; } shift(array, 0, array.length, offset);}//原有调用swap的方法省略//给出rotate方式实现,比swap方式快3倍public static void rotate(int[] array, int startIndexInclusive, int endIndexExclusive, int offset) { rotate(array, startIndexInclusive, endIndexExclusive - offset); rotate(array, endIndexExclusive - offset, endIndexExclusive); rotate(array, startIndexInclusive, endIndexExclusive);}public static void rotate(int[] array, int startIndexInclusive, int endIndexExclusive) { if (array == null || array.length == 0 || startIndexInclusive >= array.length || endIndexExclusive >= array.length) { return; } if (startIndexInclusive < 0) { startIndexInclusive = 0; } if (endIndexExclusive < 0) { endIndexExclusive = 0; } int low = startIndexInclusive; int high = endIndexExclusive - 1; while (low < high) { int tmp = array[low]; array[low] = array[high]; array[high] = tmp; low++; high--; }}
indexOf、lastIndexOf方法
- 遍历一遍数组,找不到就返回INDEX_NOT_FOUND
- 浮点类型多一个精度参数,用以判断偏差在什么范围内为相等
- 最后一个参数startIndex默认为0,若有带入,则指示从哪个位置开始搜索
int indexOf(final boolean[] array, final boolean valueToFind, int startIndex)
contains方法
- 调用indexOf方法,判断返回值是否为INDEX_NOT_FOUND
toPrimitive方法
- 将封箱类型数组转换成基本类型数组,第一个方法元素不能为空(因为有调用获取值得方法),否则会抛出NPE;第二个方法可以在元素为空时转成设定的默认值
//元素不能为空public static char[] toPrimitive(final Character[] array) { if (array == null) { return null; } else if (array.length == 0) { return EMPTY_CHAR_ARRAY; } final char[] result = new char[array.length]; for (int i = 0; i < array.length; i++) { result[i] = array[i].charValue(); } return result;}//元素可为空,为空时用valueForNull填充//核心代码for (int i = 0; i < array.length; i++) { final Character b = array[i]; result[i] = (b == null ? valueForNull : b.charValue());}return result;
toObject方法
- 将基本类型数组转换成封箱类型数组
public static Character[] toObject(final char[] array) { if (array == null) { return null; } else if (array.length == 0) { return EMPTY_CHARACTER_OBJECT_ARRAY; } final Character[] result = new Character[array.length]; for (int i = 0; i < array.length; i++) { result[i] = Character.valueOf(array[i]); } return result;}
isEmpty方法、isNotEmpty方法
- isEmpty判断数组是否为null或长度是否为0
- isNotEmpty与isEmpty相反
addAll方法
- 创建一个新数组,包含传入的参数数组的全部元素
- 核心是System.arraycopy方法
add方法
- 创建一个新数组,长度是原始数组长度加1,新数组按原数组顺序容纳其所有元素
- 在新数组最后一个位置插入新元素
remove方法
- 删除指定位置的元素
- 调用System.arraycopy实现
//核心代码public static int[] remove(final int[] array, final int index) { return (int[]) remove((Object) array, index);}private static Object remove(final Object array, final int index) { final int length = getLength(array); if (index < 0 || index >= length) { throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length); } final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1); System.arraycopy(array, 0, result, 0, index); if (index < length - 1) { System.arraycopy(array, index + 1, result, index, length - index - 1); } return result;}
- removeElement方法;可进行批量删除(调用removeAll实现)
- removeAll方法删除指定位置的元素,一次可以删除多个
removeElement方法
- 先查找待删除元素第一次出现的位置,然后调用remove方法删除元素
final int index = indexOf(array, element);if (index == INDEX_NOT_FOUND) { return clone(array);}return remove(array, index);
public static short[] removeElements(final short[] array, final short... values) { if (isEmpty(array) || isEmpty(values)) { return clone(array); } final HashMap<Short, MutableInt> occurrences = new HashMap<>(values.length); for (final short v : values) { final Short boxed = Short.valueOf(v); final MutableInt count = occurrences.get(boxed); if (count == null) { occurrences.put(boxed, new MutableInt(1)); } else { count.increment(); } } final BitSet toRemove = new BitSet(); for (int i = 0; i < array.length; i++) { final short key = array[i]; final MutableInt count = occurrences.get(key); if (count != null) { if (count.decrementAndGet() == 0) { occurrences.remove(key); } toRemove.set(i); } } return (short[]) removeAll(array, toRemove);}
removeAll方法
public static byte[] removeAll(final byte[] array, final int... indices) { return (byte[]) removeAll((Object) array, indices);}static Object removeAll(final Object array, final int... indices) { final int length = getLength(array); int diff = 0; // number of distinct indexes, i.e. number of entries that will be removed //对indices进行拷贝并排序 // identify length of result array if (isNotEmpty(clonedIndices)) { //计算需要删除元素的个数diff } // create result array,并循环调用System.arraycopy return result;}
removeElements方法
- 先找出所有要删除元素的位置,然调用removeAll方法
public static byte[] removeElements(final byte[] array, final byte... values) { if (isEmpty(array) || isEmpty(values)) { return clone(array); } final Map<Byte, MutableInt> occurrences = new HashMap<>(values.length); for (final byte v : values) { final Byte boxed = Byte.valueOf(v); final MutableInt count = occurrences.get(boxed); if (count == null) { occurrences.put(boxed, new MutableInt(1)); } else { count.increment(); } } final BitSet toRemove = new BitSet(); for (int i = 0; i < array.length; i++) { final byte key = array[i]; final MutableInt count = occurrences.get(key); if (count != null) { if (count.decrementAndGet() == 0) { occurrences.remove(key); } toRemove.set(i); } } return (byte[]) removeAll(array, toRemove);}
isSorted方法
- 判断数组是否非降序排列
- 空数组及长度小于2的数组是非降序的
//核心代码boolean previous = array[0];final int n = array.length;for (int i = 1; i < n; i++) { final boolean current = array[i]; if (BooleanUtils.compare(previous, current) > 0) { return false; } previous = current;}return true;
removeAllOccurences方法
- 移除数组中出现的所有指定元素
- 先查找所有满足条件的元素的位置,然后调用removeAll
//核心代码return removeAll(array, Arrays.copyOf(indices, count));
toStringArray
- 转换成字符串数组,若元素为空,则跑出NPE,但若是指定了元素为空时的默认值,则用默认值填充
//核心代码1,元素不能为空//String[] toStringArray(final Object[] array)final String[] result = new String[array.length];for (int i = 0; i < array.length; i++) { result[i] = array[i].toString();}//核心代码2,有填充//String[] toStringArray(final Object[] array, final String valueForNullElements)final String[] result = new String[array.length];for (int i = 0; i < array.length; i++) { final Object object = array[i]; result[i] = (object == null ? valueForNullElements : object.toString());}
insert方法
- 创建一个新数组
- 调用System.arraycopy方法拷贝原数组插入位置之前的所有元素
- 在指定位置插入新元素
- 调用System.arraycopy方法拷贝原数组剩余的元素
//核心代码//拷贝所有待插入元素到新数组index开始的位置System.arraycopy(values, 0, result, index, values.length);//拷贝原数组前index个元素到新数组if (index > 0) { System.arraycopy(array, 0, result, 0, index);}//拷贝原数组index及之后的元素到新数组if (index < array.length) { System.arraycopy(array, index, result, index + values.length, array.length - index);}
shuffle方法
- 打乱数组元素,在原数组上操作
- 遍历一遍数组,与随机生成的位置上的元素交换
//核心代码//遍历数组元素,使得元素与随机位置上的元素进行交换for (int i = array.length; i > 1; i--) { swap(array, i - 1, random.nextInt(i), 1);}
阅读全文
0 0
- org.apache.commons.lang3.ArrayUtils源码分析
- ArrayUtils 源码阅读有感 :) (commons-lang3)
- org.apache.commons.lang.ArrayUtils
- org.apache.commons.lang.ArrayUtils
- org.apache.commons.lang3.StringUtils
- Apache-Commons-lang3.5 ArrayUtils常用方法总结
- org.apache.commons.lang.ArrayUtils记录
- org.apache.commons.lang3功能示例
- org.apache.commons.lang3功能示例
- org.apache.commons.lang3功能示例
- NoClassDefFoundError: org/apache/commons/lang3/StringUtils.....
- org.apache.commons.lang3功能示例
- org.apache.commons.lang3之StringUtils
- org.apache.commons.lang3.StringUtils用法
- org.apache.commons.lang3功能示例
- org.apache.commons.lang3功能演示
- 判断字符串是否为空的org.apache.commons.lang3.StringUtils类方法isBlank()源码查看
- Commons lang3 包ArrayUtils类使用
- 教你如何优雅的使用React的context属性
- Redis Zinterstore 命令
- MySQL学习划重点(《MYSQL必知必会》总结)
- 【原】十分钟搞定pandas
- Qt5.9.1编译QSanguosha
- org.apache.commons.lang3.ArrayUtils源码分析
- 数据结构之栈
- 查看和修改Mysql数据库建表的时候默认的存储引擎
- 矩阵乘法
- 1042 数字0-9的数量【数位dp】
- 微信小程序地图划线
- 自己实现的LinkedList
- git 游离状态的解决办法
- CV520直接pin对pin替换 MS520,直接替换,无需修改硬件以及软件