JDK1.8源码泛读之Arrays
jdk1.8包含的常用集合工具类,一般包括两个:
数组工具类:`java.util.Arrays `
结合工具类:`java.util.Collections`
今天就结合源码对`java.util.Arrays `的功能进行总结说明。
1、排序方法 `sort`
- 8种基本类型数组排序
方法直接调用`java.util.DualPivotQuicksort`(双轴快速排序类)的相关方法进行排序。
而在该类的内部,又根据数组的大小和有序性的好坏,选择适合的排序算法。比如数组小于指定阈值,则采用使用双轴快排,如果顺序连续性好,直接使用TimSort算法,顺序连续性不好的数组直接使用了 双轴快排 + 成对插入排序。具体过程本文不叙述。可以参考:
- object[]数组排序
对对象类型的数组的排序,其过程又有别于基本类型,jdk会借助于参数:LegacyMergeSort.userRequested
进行排序算法的选择,如果开启,那么采用传统的归并排序,否则采用[TimSort]的算法。
- 并行排序方法`parallelSort`
parallelsort会把array分成不同的子数组,每个子数组用sort进行排序,最后再合并排序;整个过程用ForkJoin
common pool(java.util.concurrent.ForkJoinPool)进行并发操作
2、并行累积方法`parallelPrefix`
使用提供的函数并行累积给定数组中的每个元素。例如,如果数组最初保存[2, 1, 0, 3]并且操作执行加法,则返回时数组成立[2, 3, 3, 6]。并行前缀计算通常比大型数组的顺序循环更有效。
public static int[] intArrays ={55,45,23,11,10,88,102,99}; public static void parallelPrefix(){ System.out.println("*******调用前*******");
System.out.println(Arrays.toString(intArrays)); Arrays.parallelPrefix(intArrays,(x,y)->(x+y)); System.out.println("*******调用后*******");
System.out.println(Arrays.toString(intArrays));
}
*******排序前*******
[55, 45, 23, 11, 10, 88, 102, 99]
*******排序后*******
[55, 100, 123, 134, 144, 232, 334, 433]
55=55
100=55+45
123=55+45+23
...
433=55+...+99
3、二叉查找`binarySearch`
在已排序数组中,找出指定值的元素所在的位置(如果为正数,返回从0开始的index,如果为负数,其绝对值-1为所找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; // key found
}
return -(low + 1); // key not found.
}
4、相等性判断`equals`
数组等于比较,过程相对简单:
public static boolean equals(int[] a, int[] a2) {
//同一个对象,即引用地址一样
if (a==a2)
return true;
//一个为null
if (a==null || a2==null)
return false;
//长度不等,直接返回
int length = a.length;
if (a2.length != length)
return false;
//每个元素比较,有不同就返回
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false; return true;
}
5、批量赋值`fill`
填充数据指定或者全部位置的值为指定值,相对简单。
public static void fill(long[] a, long val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
6、复制`copyOf`
对数组元素进行复制,其中返回的是一个新的数组,但是数组元素还是对原先数组堆对象的引用(即元素浅复制)。
该方法底层调用的是native方法,进行快速复制:`system.arraycopy`
//测试示例
ArraysDemo[] demos ={new ArraysDemo("a"),new ArraysDemo("b"),new ArraysDemo("c"),new ArraysDemo("d"),new ArraysDemo("e")}; ArraysDemo[] newDemos = Arrays.copyOf(demos,demos.length); //数组对象深复制 返回false
System.out.println(demos==newDemos);
//数组元素浅复制,元素引用的还是同一个地址,返回true
System.out.println(demos[1]==newDemos[1]); newDemos[0] = new ArraysDemo("f");
//地址改变 返回false
System.out.println(demos[0]==newDemos[0]);
//元素内容改变
newDemos[1].setClassVer("bb");
//原始对象同时改变 打印bb
System.out.println(demos[1].getClassVer());
7、范围复制`copyOfRange`
数组的局部复制,最终调用6的copyOf方法。
8、返回集合`asList`
返回Arrays内部类ArrayList<>对象
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
相比较于java.util.ArrayList,缺少List接口的相关方法。
``` public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
所以List接口的相关方法无法调用。正如《阿里巴巴java开发规约》所描述的:
使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。
asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法,只是转换接口,后台数据仍旧是数组。
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
} //测试,异常 UnsupportedOperationException
List list = Arrays.asList(intArrays);
list.add(2);
其实asList内部是调用了抽闲类AbstractList的add方法,但内部类并没有重载实现。
所以:
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
9、hash计算`hashCode`
获取数组的hashcode,其内部是数组元素的hashcode的拼装,根据类型不同又有不同的拼装方式。
10、并行遍历迭代器`spliterator`
Spliterator可以理解为Iterator的Split版本(但用途要丰富很多)。使用Iterator的时候,我们可以顺序地遍历容器中的元素,使用Spliterator的时候,我们可以将元素分割成多份,分别交于不于的线程去遍历,以提高效率。使用 Spliterator 每次可以处理某个元素集合中的一个元素 — 不是从 Spliterator 中获取元素,而是使用 tryAdvance() 或 forEachRemaining() 方法对元素应用操作。但Spliterator 还可以用于估计其中保存的元素数量,而且还可以像细胞分裂一样变为一分为二。这些新增加的能力让流并行处理代码可以很方便地将工作分布到多个可用线程上完成。
11、流式处理`stream`
public static void stream(){
String [] strArray = new String[] {"a", "b", "c","d"}; //过滤操作,过滤掉为a的字符串
List afterFilterLists =Arrays.stream(strArray).filter(s -> !s.equals("a"))
.collect(Collectors.toList()); System.out.println(afterFilterLists);
//输出[b, c, d] //foreach操作 输出 a b c d
Arrays.stream(strArray).forEach(s-> System.out.println(s)); }
JDK1.8源码泛读之Arrays的更多相关文章
- JDK1.8源码(四)——java.util.Arrays类
一.概述 1.介绍 Arrays 类是 JDK1.2 提供的一个工具类,提供处理数组的各种方法,基本上都是静态方法,能直接通过类名Arrays调用. 二.类源码 1.asList()方法 将一个泛型数 ...
- 【集合框架】JDK1.8源码分析之Collections && Arrays(十)
一.前言 整个集合框架的常用类我们已经分析完成了,但是还有两个工具类我们还没有进行分析.可以说,这两个工具类对于我们操作集合时相当有用,下面进行分析. 二.Collections源码分析 2.1 类的 ...
- JDK1.8源码(四)——java.util.Arrays 类
java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用. 1.asList public static ...
- AQS源码泛读,梳理设计流程(jdk8)
一.AQS介绍 AQS(AbstractQueuedSynchronizer)抽象队列同步器,属于多线程编程的基本工具:JDK对其定义得很详细,并提供了多种常用的工具类(重入锁,读写锁,信号量,Cyc ...
- JDK1.8源码学习-String
JDK1.8源码学习-String 目录 一.String简介 String类是Java中最常用的类之一,所有字符串的字面量都是String类的实例,字符串是常量,在定义之后不能被改变. 二.定义 p ...
- 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)
一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...
- JDK1.8源码阅读系列之三:Vector
本篇随笔主要描述的是我阅读 Vector 源码期间的对于 Vector 的一些实现上的个人理解,用于个人备忘,有不对的地方,请指出- 先来看一下 Vector 的继承图: 可以看出,Vector 的直 ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
- 【1】【JUC】JDK1.8源码分析之ArrayBlockingQueue,LinkedBlockingQueue
概要: ArrayBlockingQueue的内部是通过一个可重入锁ReentrantLock和两个Condition条件对象来实现阻塞 注意这两个Condition即ReentrantLock的Co ...
随机推荐
- Mybatis手工写sql语句及Mapper.xml方法
首先在项目中 建一个mapper包,然后在spring集合mybatis的配置文件中设置扫描这个mapper包 然后,建 封装查询结果需要的 pojo 然后,在 mapper包中创建 Mapper接口 ...
- [转载]系统管理:update-alternatives
http://blog.csdn.net/dbigbear/article/details/4398961 好吧,其实博主也是转载的. update-alternatives --display | ...
- 论C++11 中vector的N种遍历方法
随着C++11标准的出现,C++标准添加了许多有用的特性,C++代码的写法也有比较多的变化. vector是经常要使用到的std组件,对于vector的遍历,本文罗列了若干种写法. (注:本文中代码为 ...
- kubernetes创建资源对象yaml文件例子--pod详解
apiVersion: v1 #指定api版本,此值必须在kubectl apiversion中 kind: Pod #指定创建资源的角色/类型 metadata: #资源的元数据/属性 name: ...
- uboot两阶段代码分析
1.启动过程特征总结(1)第一阶段为汇编阶段(start.s).第二阶段为C阶段(board.c中的start_armboot 函数)(2)第一阶段在SRAM中.第二阶段在DRAM中(3)第一阶段注重 ...
- 图书馆排序(Library Sort)
思路简介,大概意思是说,排列图书时,如果在每本书之间留一定的空隙,那么在进行插入时就有可能会少移动一些书,说白了就是在插入排序的基础上,给书与书之间留一定的空隙,这个空隙越大,需要移动的书就越少,这是 ...
- 转【es中数据节点和主机】
在生产环境下,如果不修改elasticsearch节点的角色信息,在高数据量,高并发的场景下集群容易出现脑裂等问题. 默认情况下,elasticsearch集群中每个节点都有成为主节点的资格,也都存储 ...
- mysql 并发测试
针对上一节做一些针对公司业务的测试. 我们来做一些压力测试. 服务器配置: 操作系统: centos 5.6-64 CPU: 8核 内存: 8G 硬盘:sas 文件系统:linux MySQL:5.6 ...
- Android中自定义属性attr.xml的格式详解
1. reference:参考某一资源ID. (1)属性定义: <declare-styleable name = "名称"> ...
- Linux二进制代码的阅读
大多数时候,我们研究的是如何阅读源代码.但在一些情况下,比如源代码不公开 或得到源代码的代价很高的情况下,我们又不得不需要了解程序的行为,这 时阅读二进制文件就非常重要.假设现在有一个二进制可执行文件 ...