java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各类方法,并且每一个方法基本上都是静态方法,能直接经过类名Arrays调用。java
public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
做用是返回由指定数组支持的固定大小列表。算法
注意:这个方法返回的 ArrayList 不是咱们经常使用的集合类 java.util.ArrayList。这里的 ArrayList 是 Arrays 的一个内部类 java.util.Arrays.ArrayList。这个内部类有以下属性和方法:
数组
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { if (array==null) throw new NullPointerException(); a = array; } public int size() { return a.length; } public Object[] toArray() { return a.clone(); } public <T> T[] toArray(T[] a) { int size = size(); if (a.length < size) return Arrays.copyOf(this.a, size, (Class<? extends T[]>) a.getClass()); System.arraycopy(this.a, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } public E get(int index) { return a[index]; } public E set(int index, E element) { E oldValue = a[index]; a[index] = element; return oldValue; } public int indexOf(Object o) { if (o==null) { for (int i=0; i<a.length; i++) if (a[i]==null) return i; } else { for (int i=0; i<a.length; i++) if (o.equals(a[i])) return i; } return -1; } public boolean contains(Object o) { return indexOf(o) != -1; } }
①、返回的 ArrayList 数组是一个定长列表,咱们只能对其进行查看或者修改,可是不能进行添加或者删除操做微信
经过源码咱们发现该类是没有add()或者remove() 这样的方法的,若是对其进行增长或者删除操做,都会调用其父类 AbstractList 对应的方法,而追溯父类的方法最终会抛出 UnsupportedOperationException 异常。以下:app
String[] str = {"a","b","c"}; List<String> listStr = Arrays.asList(str); listStr.set(1, "e");//能够进行修改 System.out.println(listStr.toString());//[a, e, c] listStr.add("a");//添加元素会报错 java.lang.UnsupportedOperationException
②、引用类型的数组和基本类型的数组区别dom
String[] str = {"a","b","c"}; List listStr = Arrays.asList(str); System.out.println(listStr.size());//3 int[] i = {1,2,3}; List listI = Arrays.asList(i); System.out.println(listI.size());//1
上面的结果第一个listStr.size()==3,而第二个 listI.size()==1。这是为何呢?ide
咱们看源码,在 Arrays.asList 中,方法声明为 <T> List<T> asList(T... a)。该方法接收一个可变参数,而且这个可变参数类型是做为泛型的参数。咱们知道基本数据类型是不能做为泛型的参数的,可是数组是引用类型,因此数组是能够泛型化的,因而 int[] 做为了整个参数类型,而不是 int 做为参数类型。工具
因此将上面的方法泛型化补全应该是:ui
String[] str = {"a","b","c"}; List<String> listStr = Arrays.asList(str); System.out.println(listStr.size());//3 int[] i = {1,2,3}; List<int[]> listI = Arrays.asList(i);//注意这里List参数为 int[] ,而不是 int System.out.println(listI.size());//1 Integer[] in = {1,2,3}; List<Integer> listIn = Arrays.asList(in);//这里参数为int的包装类Integer,因此集合长度为3 System.out.println(listIn.size());//3
③、返回的列表ArrayList里面的元素都是引用,不是独立出来的对象this
String[] str = {"a","b","c"}; List<String> listStr = Arrays.asList(str); //执行更新操做前 System.out.println(Arrays.toString(str));//[a, b, c] listStr.set(0, "d");//将第一个元素a改成d //执行更新操做后 System.out.println(Arrays.toString(str));//[d, b, c]
这里的Arrays.toString()方法就是打印数组的内容,后面会介绍。咱们看修改集合的内容,原数组的内容也变化了,因此这里传入的是引用类型。
④、已知数组数据,如何快速获取一个可进行增删改查的列表List?
String[] str = {"a","b","c"}; List<String> listStr = new ArrayList<>(Arrays.asList(str)); listStr.add("d"); System.out.println(listStr.size());//4
这里的ArrayList 集合类后面咱们会详细讲解,你们目前只须要知道有这种用法便可。
⑤、Arrays.asList() 方法使用场景
Arrays工具类提供了一个方法asList, 使用该方法能够将一个变长参数或者数组转换成List 。可是,生成的List的长度是固定的;可以进行修改操做(好比,修改某个位置的元素);不能执行影响长度的操做(如add、remove等操做),不然会抛出UnsupportedOperationException异常。
因此 Arrays.asList 比较适合那些已经有数组数据或者一些元素,而须要快速构建一个List,只用于读取操做,而不进行添加或删除操做的场景。
该方法是用于数组排序,在 Arrays 类中有该方法的一系列重载方法,能对7种基本数据类型,包括 byte,char,double,float,int,long,short 等都能进行排序,还有 Object 类型(实现了Comparable接口),以及比较器 Comparator 。
①、基本类型的数组
这里咱们以 int[ ] 为例看看:
int[] num = {1,3,8,5,2,4,6,7}; Arrays.sort(num); System.out.println(Arrays.toString(num));//[1, 2, 3, 4, 5, 6, 7, 8]
经过调用 sort(int[] a) 方法,将原数组按照升序的顺序排列。下面咱们经过源码看看是如何实现排序的:
public static void sort(int[] a) { DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); }
在 Arrays.sort 方法内部调用 DualPivotQuicksort.sort 方法,这个方法的源码很长,分别对于数组的长度进行了各类算法的划分,包括快速排序,插入排序,冒泡排序都有使用。详细源码能够参考这篇博客。
②、对象类型数组
该类型的数组进行排序能够实现 Comparable 接口,重写 compareTo 方法进行排序。
String[] str = {"a","f","c","d"}; Arrays.sort(str); System.out.println(Arrays.toString(str));//[a, c, d, f]
String 类型实现了 Comparable 接口,内部的 compareTo 方法是按照字典码进行比较的。
③、没有实现Comparable接口的,能够经过Comparator实现排序
Person[] p = new Person[]{new Person("zhangsan",22),new Person("wangwu",11),new Person("lisi",33)}; Arrays.sort(p,new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { if(o1 == null || o2 == null){ return 0; } return o1.getPage()-o2.getPage(); } }); System.out.println(Arrays.toString(p));
用二分法查找数组中的某个元素。该方法和 sort 方法同样,适用于各类基本数据类型以及对象。
注意:二分法是对以及有序的数组进行查找(好比先用Arrays.sort()进行排序,而后调用此方法进行查找)。找到元素返回下标,没有则返回 -1
实例:
int[] num = {1,3,8,5,2,4,6,7}; Arrays.sort(num); System.out.println(Arrays.toString(num));//[1, 2, 3, 4, 5, 6, 7, 8] System.out.println(Arrays.binarySearch(num, 2));//返回元素的下标 1
具体源码实现:
public static int binarySearch(int[] a, int key) { return binarySearch0(a, 0, a.length, key); } private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) { int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1;//取中间值下标 int midVal = a[mid];//取中间值 if (midVal < key) low = mid + 1; else if (midVal > key) high = mid - 1; else return mid; } return -(low + 1); }
拷贝数组元素。底层采用 System.arraycopy() 实现,这是一个native方法。
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
src:源数组
srcPos:源数组要复制的起始位置
dest:目的数组
destPos:目的数组放置的起始位置
length:复制的长度
注意:src 和 dest都必须是同类型或者能够进行转换类型的数组。
int[] num1 = {1,2,3}; int[] num2 = new int[3]; System.arraycopy(num1, 0, num2, 0, num1.length); System.out.println(Arrays.toString(num2));//[1, 2, 3]
/** * @param original 源数组 * @param newLength //返回新数组的长度 * @return */ 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; }
①、equals
equals 用来比较两个数组中对应位置的每一个元素是否相等。
八种基本数据类型以及对象都能进行比较。
咱们先看看 int类型的数组比较源码实现:
public static boolean equals(int[] a, int[] a2) { if (a==a2)//数组引用相等,则里面的元素必定相等 return true; if (a==null || a2==null)//两个数组其中一个为null,都返回false return false; int length = a.length; if (a2.length != length)//两个数组长度不等,返回false return false; for (int i=0; i<length; i++)//经过for循环依次比较数组中每一个元素是否相等 if (a[i] != a2[i]) return false; return true; }
在看对象数组的比较:
public static boolean equals(Object[] a, Object[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) { Object o1 = a[i]; Object o2 = a2[i]; if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return true; }
基本上也是经过 equals 来判断。
②、deepEquals
也是用来比较两个数组的元素是否相等,不过 deepEquals 可以进行比较多维数组,并且是任意层次的嵌套数组。
String[][] name1 = {{ "G","a","o" },{ "H","u","a","n"},{ "j","i","e"}}; String[][] name2 = {{ "G","a","o" },{ "H","u","a","n"},{ "j","i","e"}}; System.out.println(Arrays.equals(name1,name2));// false System.out.println(Arrays.deepEquals(name1,name2));// true
该系列方法用于给数组赋值,并能指定某个范围赋值。
//给a数组全部元素赋值 val public static void fill(int[] a, int val) { for (int i = 0, len = a.length; i < len; i++) a[i] = val; } //给从 fromIndex 开始的下标,toIndex-1结尾的下标都赋值 val,左闭右开 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; }
toString 用来打印一维数组的元素,而 deepToString 用来打印多层次嵌套的数组元素。
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(", "); } }
本系列教程持续更新,能够微信搜索「 IT可乐 」第一时间阅读。回复《电子书》有我为你们特别筛选的书籍资料