Arrays工具类使用与源码分析(1)
- Arrays工具类主要是方便数组操作的,学习好该类可以让我们在编程过程中轻松解决数组相关的问题,简化代码的开发。
- Arrays类有一个私有的构造函数,没有对外提供实例化的方法,因此无法实例化对象。因为该类是个工具类,因此使用的时候主要使用静态方法。
- 由于数组里面可包含的对象类型很多,比如int、long、float等等,因此Arrays的静态方法有很多重载的方法。我们在学习研究的过程中只需要针对一种类型研究透即可。
由于Arrays的方法很多,这一章我们主要从简单的方法进行分析。
toString方法
使用方式:
Arrays工具类的toString方法,主要将数组转换为字符串。这在我们打印数组内容的时候非常有用。
public static void main(String[] args) { int[] a = {9, 9, 9, 9, 9}; int[] b = null; int[] c = new int[10]; int[] d = {}; System.out.println(Arrays.toString(a)); System.out.println(Arrays.toString(b)); System.out.println(Arrays.toString(c)); System.out.println(Arrays.toString(d)); }
返回结果如下:
[9, 9, 9, 9, 9] null [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] []
源码分析
我们只分析一种类型的,比如整型,其余类型的代码大体类似。注意该方法没有对原有数组进行改变,只是新产生了一个包含数组内容的字符串。
public static String toString(int[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { b.append(a[i]); if (i == iMax) return b.append(']').toString(); b.append(", "); } }
-
如果数组为null,则返回 null 字符串
-
用一个变量 iMax 存储数组长度减一的值。此值如果为 -1,表示 数组长度为0,那么就返回字符串 [].
-
使用StringBuilder合并字符串,遍历数组,组装字符串。并且使用[]括起来。
fill方法
Arrays工具类的fill方法,主要将数组进行填充。比如我们新建了一个数组,之后想对其元素全部初始化为100,这个时候使用for循环进行赋值则显得麻烦,直接使用工具方法便可完成此功能。
使用方式一
public static void main(String[] args) { int[] a = {9, 9, 9, 9, 9}; Arrays.fill(a, 1);//全部置为1,将原有的9覆盖 int[] c = new int[10]; Arrays.fill(c, 3);//全部置为3,类似与赋值 int[] d = {}; Arrays.fill(d, 4);//无意义 System.out.println(Arrays.toString(a)); System.out.println(Arrays.toString(c)); System.out.println(Arrays.toString(d)); }
返回结果如下:
[1, 1, 1, 1, 1] [3, 3, 3, 3, 3, 3, 3, 3, 3, 3] []
从上面的使用方式来看,这个方法最适合新建一个数组之后,给数组赋值一个初始值,并且这个初始值并不是各个类型默认的值,如0之类的。
源码分析:非常简单,遍历赋值。
public static void fill(int[] a, int val) { for (int i = 0, len = a.length; i < len; i++) a[i] = val; }
使用方式二
对数组的部分元素填充一个值,从起始位置到结束位置,取头不取尾。
public static void main(String[] args) { int[] a = {9, 9, 9, 9, 9}; Arrays.fill(a, 1, 3, 4); //[9, 4, 4, 9, 9] System.out.println(Arrays.toString(a)); }
源码分析:这种部分赋值的方法注意需要记住方法里面的参数的含义即可,通过源码可以清楚看出:
public static void fill(int[] a, int fromIndex, int toIndex, int val) { rangeCheck(a.length, fromIndex, toIndex); for (int i = fromIndex; i < toIndex; i++) a[i] = val; }
- 第一个参数是待填充的数组
- 第二个参数是待填充数组的起始索引位置(包含)
- 第三个参数是待填充数组的结束索引位置(不包含)
- 第四个参数是要填充的数值
下面是参数校验的功能:
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); } }
copyOf方法
使用方式
copyOf方法的功能是拷贝一个数组。它内部是使用了System.arraycopy方法进行拷贝。首先看下使用方式。
public static void main(String[] args) { int[] a = {1, 2}; System.out.println(Arrays.toString(a)); //[1, 2] int[] b = Arrays.copyOf(a, 0); System.out.println(Arrays.toString(b)); //[] int[] c = Arrays.copyOf(a, 1); System.out.println(Arrays.toString(c)); //[1] int[] d = Arrays.copyOf(a, 2); //实际可用a.length替代2 System.out.println(Arrays.toString(d)); //[1, 2] int[] e = Arrays.copyOf(a, 3); System.out.println(Arrays.toString(e)); //[1, 2, 0] }
源码分析:
public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
该方法需要一个原数组和一个需要生成新数组的长度这两个参数。
- 首先生成一个新数组,使用指定的长度。
- 调用System.arraycopy方法进行生成新的数组。
注意 Math.min(original.length, newLength) 的含义是,如果传入的长度大于原数组的长度,则使用原数组的长度,否则使用新传入的数组长度。
System.arraycopy介绍
/* * @param src 原数组. * @param srcPos 从元数据的起始位置开始. * @param dest 目标数组. * @param destPos 目标数组的开始起止位置. * @param length 要拷贝的数组长度. * @exception IndexOutOfBoundsException if copying would cause * access of data outside array bounds. * @exception ArrayStoreException if an element in the <code>src</code> * array could not be stored into the <code>dest</code> array * because of a type mismatch. * @exception NullPointerException if either <code>src</code> or * <code>dest</code> is <code>null</code>. */ public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
示例:
public static void main(String[] args) { int[] x = {1, 2, 3, 4, 5, 6, 7}; int[] y = {11, 12, 13, 14, 15, 16, 17}; System.arraycopy(x, 1, y, 1, 5); System.out.println(Arrays.toString(x));//[1, 2, 3, 4, 5, 6, 7] System.out.println(Arrays.toString(y));//[11, 2, 3, 4, 5, 6, 17] }
System.arraycopy(x, 1, y, 1, 5); 这句的含义是:
将x数组从第二个位置起拿出5个元素,放置到y数组的第二个位置及以后。
copyOfRange方法
copyOfRange方法同样也是拷贝一个数组,只是拷贝的时候需要指定起始位置和结束位置。而copyOf只能传递拷贝的元素的个数,并且是从原数组的第一个元数开始拷贝。
使用方式:
public static void main(String[] args) { int[] a = {1, 2, 3, 4, 5, 6}; System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 5, 6] int[] b = Arrays.copyOfRange(a, 1, 4); System.out.println(Arrays.toString(b)); //[2, 3, 4] int[] c = Arrays.copyOfRange(a, 1, 10); System.out.println(Arrays.toString(c)); //[2, 3, 4, 5, 6, 0, 0, 0, 0] }
源码分析:
public static int[] copyOfRange(int[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); int[] copy = new int[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; }
首先判断开始位置和结束位置是否合理,不合理就报错,然后和copyOf源码一样,,使用System.arraycopy方法进行生成新的数组。
关于copyOfRange和copyOf拷贝对象,本节不做介绍,后面会仔细分析。