JDK1.8源码(四)——java.util.Arrays 类

简介:   java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用。 1、asList public static List asList(T... a) { return new ArrayList(a); }   作用是返回由指定数组支持的固定大小列表。

  java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用。

1、asList

    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

  作用是返回由指定数组支持的固定大小列表

  注意:这个方法返回的 ArrayList 不是我们常用的集合类 java.util.ArrayList。这里的 ArrayList 是 Arrays 的一个内部类 java.util.Arrays.ArrayList。这个内部类有如下属性和方法:

  

 1     private static class ArrayList<E> extends AbstractList<E>
 2         implements RandomAccess, java.io.Serializable
 3     {
 4         private static final long serialVersionUID = -2764017481108945198L;
 5         private final E[] a;
 6 
 7         ArrayList(E[] array) {
 8             if (array==null)
 9                 throw new NullPointerException();
10             a = array;
11         }
12 
13         public int size() {
14             return a.length;
15         }
16 
17         public Object[] toArray() {
18             return a.clone();
19         }
20 
21         public <T> T[] toArray(T[] a) {
22             int size = size();
23             if (a.length < size)
24                 return Arrays.copyOf(this.a, size,
25                                      (Class<? extends T[]>) a.getClass());
26             System.arraycopy(this.a, 0, a, 0, size);
27             if (a.length > size)
28                 a[size] = null;
29             return a;
30         }
31 
32         public E get(int index) {
33             return a[index];
34         }
35 
36         public E set(int index, E element) {
37             E oldValue = a[index];
38             a[index] = element;
39             return oldValue;
40         }
41 
42         public int indexOf(Object o) {
43             if (o==null) {
44                 for (int i=0; i<a.length; i++)
45                     if (a[i]==null)
46                         return i;
47             } else {
48                 for (int i=0; i<a.length; i++)
49                     if (o.equals(a[i]))
50                         return i;
51             }
52             return -1;
53         }
54 
55         public boolean contains(Object o) {
56             return indexOf(o) != -1;
57         }
58     }
View Code

  ①、返回的 ArrayList 数组是一个定长列表,我们只能对其进行查看或者修改,但是不能进行添加或者删除操作

  通过源码我们发现该类是没有add()或者remove() 这样的方法的,如果对其进行增加或者删除操作,都会调用其父类 AbstractList 对应的方法,而追溯父类的方法最终会抛出 UnsupportedOperationException 异常。如下:

1 String[] str = {"a","b","c"};
2 List<String> listStr = Arrays.asList(str);
3 listStr.set(1, "e");//可以进行修改
4 System.out.println(listStr.toString());//[a, e, c]
5 listStr.add("a");//添加元素会报错 java.lang.UnsupportedOperationException 

  

  ②、引用类型的数组和基本类型的数组区别

1 String[] str = {"a","b","c"};
2 List listStr = Arrays.asList(str);
3 System.out.println(listStr.size());//3
4 
5 int[] i = {1,2,3};
6 List listI = Arrays.asList(i);
7 System.out.println(listI.size());//1

  上面的结果第一个listStr.size()==3,而第二个 listI.size()==1。这是为什么呢?

  我们看源码,在 Arrays.asList 中,方法声明为  <T> List<T> asList(T... a)。该方法接收一个可变参数,并且这个可变参数类型是作为泛型的参数。我们知道基本数据类型是不能作为泛型的参数的,但是数组是引用类型,所以数组是可以泛型化的,于是 int[] 作为了整个参数类型,而不是 int 作为参数类型。

  所以将上面的方法泛型化补全应该是:

 1 String[] str = {"a","b","c"};
 2 List<String> listStr = Arrays.asList(str);
 3 System.out.println(listStr.size());//3
 4 
 5 int[] i = {1,2,3};
 6 List<int[]> listI = Arrays.asList(i);//注意这里List参数为 int[] ,而不是 int
 7 System.out.println(listI.size());//1
 8 
 9 Integer[] in = {1,2,3};
10 List<Integer> listIn = Arrays.asList(in);//这里参数为int的包装类Integer,所以集合长度为3
11 System.out.println(listIn.size());//3

  ③、返回的列表ArrayList里面的元素都是引用,不是独立出来的对象

1 String[] str = {"a","b","c"};
2 List<String> listStr = Arrays.asList(str);
3 //执行更新操作前
4 System.out.println(Arrays.toString(str));//[a, b, c]
5 listStr.set(0, "d");//将第一个元素a改为d
6 //执行更新操作后
7 System.out.println(Arrays.toString(str));//[d, b, c]

  这里的Arrays.toString()方法就是打印数组的内容,后面会介绍。我们看修改集合的内容,原数组的内容也变化了,所以这里传入的是引用类型。

  ④、已知数组数据,如何快速获取一个可进行增删改查的列表List?

1 String[] str = {"a","b","c"};
2 List<String> listStr = new ArrayList<>(Arrays.asList(str));
3 listStr.add("d");
4 System.out.println(listStr.size());//4

  这里的ArrayList 集合类后面我们会详细讲解,大家目前只需要知道有这种用法即可。

  ⑤、Arrays.asList() 方法使用场景

  Arrays工具类提供了一个方法asList, 使用该方法可以将一个变长参数或者数组转换成List 。但是,生成的List的长度是固定的;能够进行修改操作(比如,修改某个位置的元素);不能执行影响长度的操作(如add、remove等操作),否则会抛出UnsupportedOperationException异常。

  所以 Arrays.asList 比较适合那些已经有数组数据或者一些元素,而需要快速构建一个List,只用于读取操作,而不进行添加或删除操作的场景。

2、sort

  该方法是用于数组排序,在 Arrays 类中有该方法的一系列重载方法,能对7种基本数据类型,包括 byte,char,double,float,int,long,short 等都能进行排序,还有 Object 类型(实现了Comparable接口),以及比较器 Comparator 。

  

  ①、基本类型的数组

  这里我们以 int[ ] 为例看看:

1 int[] num = {1,3,8,5,2,4,6,7};
2 Arrays.sort(num);
3 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 方法进行排序。

1 String[] str = {"a","f","c","d"};
2 Arrays.sort(str);
3 System.out.println(Arrays.toString(str));//[a, c, d, f]

  String 类型实现了 Comparable 接口,内部的 compareTo 方法是按照字典码进行比较的。

  ③、没有实现Comparable接口的,可以通过Comparator实现排序

 1 Person[] p = new Person[]{new Person("zhangsan",22),new Person("wangwu",11),new Person("lisi",33)};
 2 Arrays.sort(p,new Comparator<Person>() {
 3     @Override
 4     public int compare(Person o1, Person o2) {
 5         if(o1 == null || o2 == null){
 6             return 0;
 7         }
 8         return o1.getPage()-o2.getPage();
 9     }
10 });    
11 System.out.println(Arrays.toString(p));

3、binarySearch

  用二分法查找数组中的某个元素。该方法和 sort 方法一样,适用于各种基本数据类型以及对象。

  注意:二分法是对以及有序的数组进行查找(比如先用Arrays.sort()进行排序,然后调用此方法进行查找)。找到元素返回下标,没有则返回 -1

  实例:

1 int[] num = {1,3,8,5,2,4,6,7};
2 Arrays.sort(num);
3 System.out.println(Arrays.toString(num));//[1, 2, 3, 4, 5, 6, 7, 8]
4 System.out.println(Arrays.binarySearch(num, 2));//返回元素的下标 1

  具体源码实现:

 1     public static int binarySearch(int[] a, int key) {
 2         return binarySearch0(a, 0, a.length, key);
 3     }
 4     private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) {
 5         int low = fromIndex;
 6         int high = toIndex - 1;
 7         
 8         while (low <= high) {
 9             int mid = (low + high) >>> 1;//取中间值下标
10             int midVal = a[mid];//取中间值
11             
12             if (midVal < key)
13             low = mid + 1;
14             else if (midVal > key)
15             high = mid - 1;
16             else
17             return mid; 
18         }
19         return -(low + 1); 
20     }
View Code

4、copyOf

  拷贝数组元素。底层采用 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;
    }

5、equals 和 deepEquals

  ①、equals

  equals 用来比较两个数组中对应位置的每个元素是否相等。

  

  八种基本数据类型以及对象都能进行比较。

  我们先看看 int类型的数组比较源码实现:

 1     public static boolean equals(int[] a, int[] a2) {
 2         if (a==a2)//数组引用相等,则里面的元素一定相等
 3             return true;
 4         if (a==null || a2==null)//两个数组其中一个为null,都返回false
 5             return false;
 6 
 7         int length = a.length;
 8         if (a2.length != length)//两个数组长度不等,返回false
 9             return false;
10 
11         for (int i=0; i<length; i++)//通过for循环依次比较数组中每个元素是否相等
12             if (a[i] != a2[i])
13                 return false;
14 
15         return true;
16     }
View Code

  在看对象数组的比较:

 1     public static boolean equals(Object[] a, Object[] a2) {
 2         if (a==a2)
 3             return true;
 4         if (a==null || a2==null)
 5             return false;
 6 
 7         int length = a.length;
 8         if (a2.length != length)
 9             return false;
10 
11         for (int i=0; i<length; i++) {
12             Object o1 = a[i];
13             Object o2 = a2[i];
14             if (!(o1==null ? o2==null : o1.equals(o2)))
15                 return false;
16         }
17 
18         return true;
19     }
View Code

  基本上也是通过 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

6、fill

  该系列方法用于给数组赋值,并能指定某个范围赋值。

    //给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;
    }

7、toString 和 deepToString

  toString 用来打印一维数组的元素,而 deepToString 用来打印多层次嵌套的数组元素。

 1     public static String toString(int[] a) {
 2         if (a == null)
 3             return "null";
 4         int iMax = a.length - 1;
 5         if (iMax == -1)
 6             return "[]";
 7 
 8         StringBuilder b = new StringBuilder();
 9         b.append('[');
10         for (int i = 0; ; i++) {
11             b.append(a[i]);
12             if (i == iMax)
13                 return b.append(']').toString();
14             b.append(", ");
15         }
16     }
View Code

 

参考文档:https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html

作者: YSOcean
本文版权归作者所有,欢迎转载,但未经作者同意不能转载,否则保留追究法律责任的权利。
目录
相关文章
|
21天前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
59 7
|
1月前
|
数据采集 人工智能 Java
Java产科专科电子病历系统源码
产科专科电子病历系统,全结构化设计,实现产科专科电子病历与院内HIS、LIS、PACS信息系统、区域妇幼信息平台的三级互联互通,系统由门诊系统、住院系统、数据统计模块三部分组成,它管理了孕妇从怀孕开始到生产结束42天一系列医院保健服务信息。
32 4
|
1月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
148 57
|
4天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
13天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
77 13
|
27天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
54 12
|
21天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
53 8
|
23天前
|
人工智能 移动开发 安全
家政上门系统用户端、阿姨端源码,java家政管理平台源码
家政上门系统基于互联网技术,整合大数据分析、AI算法和现代通信技术,提供便捷高效的家政服务。涵盖保洁、月嫂、烹饪等多元化服务,支持多终端访问,具备智能匹配、在线支付、订单管理等功能,确保服务透明、安全,适用于家庭生活的各种需求场景,推动家政市场规范化发展。
|
1月前
|
Java Android开发
Eclipse 创建 Java 类
Eclipse 创建 Java 类
29 0