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&ltObject, Object&gt 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);}
原创粉丝点击