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 ...
随机推荐
- Spring面试,IoC和AOP的理解(转)
spring 的优点?1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易实 ...
- ADS 安装失败后在此安装在Modify Repair Remove界面循环问题解决
估计是因为Win7和ADS不兼容的原因,第一次安装ADS后一直停在100%的位置,等了好久也没有反应.于是我点了Cancel.准备从新安装,于是就发生了下面的问题:一直在Modify Repair R ...
- spring cloud config的bootstrap.yml与application.proterties的区别
bootstrap.yml 和application.yml 都可以用来配置参数 bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的 application.ym ...
- JS鼠标滚轮事件解析
一.不同浏览器的鼠标滚轮事件 首先,不同的浏览器有不同的滚轮事件.主要是有两种,onmousewheel(IE/Opera/Chrome支持,firefox不支持)和DOMMouseScroll(只有 ...
- java线程的基本概念
进程和线程 进程的诞生 操作系统中有2个任务A,B,任务A先执行,执行到一半需要io,因此要大量时间,在这个时间段内cpu是空闲的,浪费了资源,于是就有进程,当A暂时无法利用cpu,但是又不能销毁时, ...
- Golang向Templates 插入对象的值
Go对象可以插入到template中,然后把对象的值表现在template中,你可以一层层的分解这个对象,去找他的子字段,当前对象用'.'来表示,所以当当前对象是一个string的时候,你可以用{{. ...
- 【uva12232/hdu3461】带权并查集维护异或值
题意: 对于n个数a[0]~a[n-1],但你不知道它们的值,通过逐步提供给你的信息,你的任务是根据这些信息回答问题: I P V :告诉你a[P] = V I P Q V:告诉你a[P] XOR a ...
- 【poj1222-又一道开关问题】高斯消元求解异或方程组
题意:给出一个5*6的图,每个灯泡有一个初始状态,1表示亮,0表示灭.每对一个灯泡操作时,会影响周围的灯泡改变亮灭,问如何操作可以使得所有灯泡都关掉. 题解: 这题和上一题几乎完全一样..就是要输出解 ...
- 【51NOD-0】1118 机器人走方格
[算法]DP #include<cstdio> #include<algorithm> using namespace std; ,maxn=; int f[maxn][max ...
- Spring理论基础-面向切面编程
AOP是Aspect-Oriented Programming的缩写,中文翻译是面向切面编程.作为Spring的特征之一,是要好好学习的. 首先面向切面编程这个名称很容易让人想起面向对象编程(OOP) ...