JDK1.8源码(四)——java.util.Arrays类
一、概述
1、介绍
Arrays 类是 JDK1.2 提供的一个工具类,提供处理数组的各种方法,基本上都是静态方法,能直接通过类名Arrays调用。
二、类源码
1、asList()方法
将一个泛型数组转化为List集合返回。但是,这个List集合既不是ArrayList实例,也不是Vector实例。它是一个固定长度的 List 集合,是 Arrays 的一个内部类 java.util.Arrays.ArrayList。
代码示例:使用
1 public class Main {
2 public static void main(String[] args) throws Exception {
3 Integer[] d = {3, 1, 2};
4 final List<Integer> integers = Arrays.asList(d);
5 System.out.println(integers);
6 }
7 }
8
9 // 结果
10 [3, 1, 2]
源码示例:
1 public static <T> List<T> asList(T... a) {
2 return new ArrayList<>(a);
3 }
4
5 private static class ArrayList<E> extends AbstractList<E>
6 implements RandomAccess, java.io.Serializable
7 {
8 // 源码省略,读者可自行用idea查看
9 }
说明:
①、定长列表,只能对其进行查看或者修改,不能进行添加或者删除操作
1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4 List<String> list = Arrays.asList(str);
5 // 可以进行修改
6 list.set(1, "e");
7 System.out.println(list.toString()); // [a, e, c]
8
9 list.add("a"); //添加元素会报错 java.lang.UnsupportedOperationException
10 }
11 }
查看源码发现,该类没有add() 和 remove()方法。如果对其进行增加或者删除操作,会调用其父类 AbstractList 对应的方法,而追溯父类的方法最终会抛出 UnsupportedOperationException 异常。源码如下:
1 // 类 AbstractList
2 public boolean add(E e) {
3 add(size(), e);
4 return true;
5 }
6
7 public void add(int index, E element) {
8 throw new UnsupportedOperationException();
9 }
②、引用类型的数组和基本类型的数组区别
1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4 final List<String> list = Arrays.asList(str);
5 System.out.println(list.size()); // 3
6
7 int[] i = {1, 2, 3};
8 final List<int[]> ints = Arrays.asList(i);
9 System.out.println(ints.size()); // 1
10
11 Integer[] in = {1, 2, 3};
12 final List<Integer> integers = Arrays.asList(in);
13 System.out.println(integers.size()); // 3
14 }
15 }
类类型才是泛型,基本数据类型不能作为泛型的参数。读者根据上面结果自行体会一下。
③、返回的是原数组的里的引用,不是独立出来的集合对象
1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4 List<String> listStr = Arrays.asList(str);
5 System.out.println(Arrays.toString(str)); // [a, b, c]
6
7 listStr.set(0, "d");
8
9 System.out.println(Arrays.toString(str)); // [d, b, c]
10 }
11 }
这里,修改的是返回的集合的内容,但是原数组的内容也变化了,所以只是返回了原数组的一个视图。如果希望返回一个全新的集合,可以如下:
1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4
5 ArrayList<String> strings = new ArrayList<>(Arrays.asList(str));
6 strings.add("d");
7
8 System.out.println(Arrays.toString(str)); // [a, b, c]
9 System.out.println(strings); // [a, b, c, d]
10 }
11 }
2、sort()方法
用于数组排序,有一系列重载方法。注意,如果是 Object 类型,需要实现Comparable接口或者传入一个比较器 Comparator ,使其具有可比性。可以参考这篇。Java比较器。
源码示例:
1 public static void sort(int[] a) {
2 DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
3 }
这个方法的源码很长,分别对数组的长度进行了各种算法的划分,包括快速排序,插入排序,冒泡排序都有使用。详细源码可以参考这篇博客。
3、binarySearch()方法
用于数组查找,是基于二分查找算法实现,有一系列重载方法,适用于各种基本数据类型以及对象数组。
值得注意的是:调用此方法,要求待查找的数组有序。存在,返回元素下标;不存在,返回一个负数(不是 -1)。
源码示例:
1 public static int binarySearch(int[] a, int key) {
2 return binarySearch0(a, 0, a.length, key);
3 }
4
5 // 典型的二分查找算法
6 private static int binarySearch0(int[] a, int fromIndex, int toIndex,
7 int key) {
8 int low = fromIndex;
9 int high = toIndex - 1;
10
11 while (low <= high) {
12 int mid = (low + high) >>> 1;
13 int midVal = a[mid];
14
15 if (midVal < key)
16 low = mid + 1;
17 else if (midVal > key)
18 high = mid - 1;
19 else
20 return mid; // key found
21 }
22
23 // 找不到,返回并不是 -1
24 return -(low + 1); // key not found.
25 }
4、copyOf()方法
拷贝数组元素。底层采用 System.arraycopy() 实现,这是一个native方法。
注意:这个方法在ArrayList源码扩容时,也是用的它。
代码示例:
1 public class Main {
2 public static void main(String[] args) {
3 int[] old = {1, 3, 2};
4
5 int[] ints = Arrays.copyOf(old, 5);
6 System.out.println(Arrays.toString(ints)); // [1, 3, 2, 0, 0]
7
8 int[] ints1 = Arrays.copyOf(old, 1);
9 System.out.println(Arrays.toString(ints1)); // [1]
10 }
11 }
源码示例:
1 // Arrays类
2 public static int[] copyOf(int[] original, int newLength) {
3 int[] copy = new int[newLength];
4 System.arraycopy(original, 0, copy, 0,
5 // 长度是旧数组长度 与 新长度 取小
6 Math.min(original.length, newLength));
7 return copy;
8 }
9
10 // System类
11 public static native void arraycopy(Object src, int srcPos,
12 Object dest, int destPos,
13 int length);
src:源数组
srcPos:源数组要复制的起始位置
dest:目的数组
destPos:目的数组放置的起始位置
length:复制的长度
注意:src 和 dest都必须是同类型或者可以进行转换类型的数组。
5、equals()/deepEquals()方法
①、equals
用于比较两个数组中对应位置的每一个元素是否相等。
源码示例:
1 // 基本数据类型数组比较
2 public static boolean equals(int[] a, int[] a2) {
3 // 引用相等,则相同
4 if (a==a2)
5 return true;
6 if (a==null || a2==null)
7 return false;
8
9 int length = a.length;
10 // 长度不同,则不相同
11 if (a2.length != length)
12 return false;
13
14 // 循环依次比较数组中每个元素是否相等
15 for (int i=0; i<length; i++)
16 if (a[i] != a2[i])
17 return false;
18
19 return true;
20 }
21
22 // 引用类型数组比较
23 public static boolean equals(Object[] a, Object[] a2) {
24 if (a==a2)
25 return true;
26 if (a==null || a2==null)
27 return false;
28
29 int length = a.length;
30 if (a2.length != length)
31 return false;
32
33 for (int i=0; i<length; i++) {
34 Object o1 = a[i];
35 Object o2 = a2[i];
36
37 // 对象相同通过 equals 方法判断
38 if (!(o1==null ? o2==null : o1.equals(o2)))
39 return false;
40 }
41
42 return true;
43 }
②、deepEquals
比较两个数组的元素是否相等,可以嵌套任意层次的数组。
源码就是递归的使用 deepEquals 判断每一层的数组是否相同。
代码示例:
1 public class Main {
2 public static void main(String[] args) {
3 String[][] name1 = {{"G", "a", "o"}, {"H", "u", "a", "n"}, {"j", "i", "e"}};
4 String[][] name2 = {{"G", "a", "o"}, {"H", "u", "a", "n"}, {"j", "i", "e"}};
5
6 System.out.println(Arrays.equals(name1, name2));// false
7 System.out.println(Arrays.deepEquals(name1, name2));// true
8 }
9 }
6、fill()方法
该系列方法用于给数组赋值,并能指定某个范围赋值。
代码示例:
1 public class Main {
2 public static void main(String[] args) {
3 int[] arr = new int[4];
4 System.out.println(Arrays.toString(arr)); // [0, 0, 0, 0]
5
6 Arrays.fill(arr, 6);
7 System.out.println(Arrays.toString(arr)); // [6, 6, 6, 6]
8 }
9 }
源码示例:
1 // 不写注释也能看懂的代码
2 public static void fill(int[] a, int val) {
3 for (int i = 0, len = a.length; i < len; i++)
4 a[i] = val;
5 }
6
7 public static void fill(int[] a, int fromIndex, int toIndex, int val) {
8 rangeCheck(a.length, fromIndex, toIndex);
9 for (int i = fromIndex; i < toIndex; i++)
10 a[i] = val;
11 }
7、toString 和 deepToString方法
toString 用来打印一维数组的元素,而 deepToString 用来打印多层次嵌套的数组元素。
参考文档:https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
JDK1.8源码(四)——java.util.Arrays类的更多相关文章
- JDK1.8源码(四)——java.util.Arrays 类
java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用. 1.asList public static ...
- JDK1.8源码(五)——java.util.Vector类
JDK1.8源码(五)--java.lang. https://www.cnblogs.com/IT-CPC/p/10897559.html
- JDK1.8源码(七)——java.util.HashMap 类
本篇博客我们来介绍在 JDK1.8 中 HashMap 的源码实现,这也是最常用的一个集合.但是在介绍 HashMap 之前,我们先介绍什么是 Hash表. 1.哈希表 Hash表也称为散列表,也有直 ...
- JDK1.8源码(五)——java.util.ArrayList 类
关于 JDK 的集合类的整体介绍可以看这张图,本篇博客我们不系统的介绍整个集合的构造,重点是介绍 ArrayList 类是如何实现的. 1.ArrayList 定义 ArrayList 是一个用数组实 ...
- JDK1.8源码(六)——java.util.LinkedList 类
上一篇博客我们介绍了List集合的一种典型实现 ArrayList,我们知道 ArrayList 是由数组构成的,本篇博客我们介绍 List 集合的另一种典型实现 LinkedList,这是一个有链表 ...
- JDK1.8源码(九)——java.util.LinkedHashMap 类
前面我们介绍了 Map 集合的一种典型实现 HashMap ,关于 HashMap 的特性,我们再来复习一遍: ①.基于JDK1.8的HashMap是由数组+链表+红黑树组成,相对于早期版本的 JDK ...
- JDK1.8源码(十一)——java.util.TreeMap类
在前面几篇博客分别介绍了这样几种集合,基于数组实现的ArrayList 类,基于链表实现的LinkedList 类,基于散列表实现的HashMap 类,本篇博客我们来介绍另一种数据类型,基于树实现的T ...
- JDK1.8源码(八)——java.util.HashSet 类
在上一篇博客,我们介绍了 Map 集合的一种典型实现 HashMap ,在 JDK1.8 中,HashMap 是由 数组+链表+红黑树构成,相对于早期版本的 JDK HashMap 实现,新增了红黑树 ...
- JDK1.8源码(十)——java.util.LinkedHashSet类
同 HashSet 与 HashMap 的关系一样,本篇博客所介绍的 LinkedHashSet 和 LinkedHashMap 也是一致的.在 JDK 集合框架中,类似 Set 集合通常都是由对应的 ...
随机推荐
- 使用JDBC(Dbutils工具包)来从数据库拿取map类型数据来动态生成insert语句
前言: 大家在使用JDBC来连接数据库时,我们通过Dbutils工具来拿取数据库中的数据,可以使用new BeanListHandler<>(所映射的实体类.class),这样得到的数据, ...
- DHCP服务-自动管理IP地址和分配固定IP
dhcp服务 端口:67 配置文件:/etc/dhcp/dhcpd.conf 自动分配IP: 一. 安装服务:yum install dhcp 安装过程省略 二.首先,看到配置文件中啥也没有,他的配置 ...
- Linux修改Ip简单知识了解
1. 在终端输入:vim /etc/sysconfig/network-scripts/ifcfg-etho(etho是指的安装centos的产生的网卡) 2.按i开始编辑,填写ip地址.子网掩码.网 ...
- 题解 Cicada 拿衣服
传送门 神仙题! 听@Yubai给我讲了半个下午,快%@Yubai 见到这些奇奇怪怪的题是不是应该试着证下状态数上界啊 首先观察题目里给的柿子,可以发现 \(or-and\) 单调增, \(min-m ...
- 【版本管理工具】git的介绍及常用命令总结
1 git简介 1.1 git是什么? "Git 是一个分布式版本控制软件,与CVS.Subversion一类的集中式版本控制工具不同,它采用了分布式版本库的作法,不需要服务器端软件,就可 ...
- C++继承体系中的内存对齐
本篇随笔讨论一个比较冷门的知识,继承结构中内存对齐的问题,如今内存越来越大也越来越便宜,大部分人都已经不再关注内存对齐的问题了.但是作为一个有追求的技术人员,实现功能永远都是最基本的要求,把代码优化到 ...
- Linux的wget命令详解
[转载] Linux wget是一个下载文件的工具,它用在命令行下.对于Linux用户是必不可少的工具,尤其对于网络管理员,经常要下载一些软件或从远程服务器恢复备份到本地服务器.如果我们使用虚拟主机, ...
- 数据库中sql分类
-- sql语句分类:-- 1)数据定义语句(DDL):-- create/alter/drop-- 2)数据操作语句(DML):-- insert ...
- 【C语言】第5章 循环结构程序设计
第5章 循环结构程序设计 三种基本循环控制结构 使用while语句实现循环 先判断条件表达式,后执行循环体语句 while (循环条件表达式) { 循环体 } 用do-while语句实现循环 先无条件 ...
- Spring Data JPA实体的生命周期总结
目录 四种状态 API示例 persist remove merge refresh 参考链接 四种状态 首先以一张图,简单介绍写实体生命周期中四种状态之间的转换关系: 瞬时(New):瞬时对象,刚N ...