关于HashSet在 java7 与 java8的不同
链接:https://www.zhihu.com/question/28414001/answer/40733996
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
“不保证有序”和“保证无序”不等价,HashSet的iterator是前者而不是后者,所以在一次运行中看到有序的结果也是正常的,但不能依赖这个有序行为。
况且HashSet并不关心key的“排序”,就算其iterator“有序”通常也是说“按元素插入顺序”(LinkedHashSet就支持插入顺序遍历)。题主在此看到的所谓“有序”纯粹是个巧合。
然后我复制粘贴了题主的代码运行了一次:
$ java SetOfInteger
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 17 16 19 18 21 20 23 22 25 24 27 26 29 28
$ java -version
java version "1.7.0-internal-zing_99.99.99.99.dev"
Zing Runtime Environment for Java Applications (build 1.7.0-internal-zing_99.99.99.99.dev-b65)
Zing 64-Bit Tiered VM (build 1.7.0-zing_99.99.99.99.dev-b870-product-azlinuxM-X86_64, mixed mode)
(Zing JDK7的开发版)
就不是有序的嘛。同样在Oracle JDK7u51上也是如此:
$ java SetOfInteger
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 17 16 19 18 21 20 23 22 25 24 27 26 29 28
$ java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
换到Zing JDK8:
$ java SetOfInteger
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
$ java -version
java version "1.8.0-internal-zing_99.99.99.99.dev"
Zing Runtime Environment for Java Applications (build 1.8.0-internal-zing_99.99.99.99.dev-b65)
Zing 64-Bit Tiered VM (build 1.8.0-zing_99.99.99.99.dev-b870-product-azlinuxM-X86_64, mixed mode)
再换到Oracle JDK8u25:
$ java SetOfInteger
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
就看到了题主说的有序行为。
JDK8的HashSet实现变了,导致元素插入的位置发生了变化;iterator自身实现的顺序倒没变,还是按照内部插入的位置顺序来遍历,于是题主就看到了JDK7和JDK8的结果不一样。具体来说,是JDK7与JDK8的java.util.HashMap的hash算法以及HashMap的数据布局发生了变化。
题主插入HashSet的是Integer,其hashCode()实现就返回int值本身。所以在对象hashCode这一步引入了巧合的“按大小排序”。
然后HashMap.hash(Object)获取了对象的hashCode()之后会尝试进一步混淆。
JDK8版java.util.HashMap内的hash算法比JDK7版的混淆程度低;在[0, 2^32-1]范围内经过HashMap.hash()之后还是得到自己。题主的例子正好落入这个范围内。外加load factor正好在此例中让这个HashMap没有hash冲突,这就导致例中元素正好按大小顺序插入在HashMap的开放式哈希表里。
根据它的实现特征,把题主的例子稍微修改一下的话:
$ cat SetOfInteger.java
import java.util.*;
public class SetOfInteger {
public static void main(String[] args){
Random rand=new Random(47);
Set<Integer> intset=new HashSet<Integer>();
for (int i=0;i<10000;i++){
intset.add(rand.nextInt(30) + (1 << 16));
}
Iterator<Integer> iterator=intset.iterator();
while (iterator.hasNext()){
System.out.print((iterator.next() - (1 << 16)) +" ");
}
}
}
$ java SetOfInteger
1 0 3 2 5 4 7 6 9 8 11 10 13 12 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28
$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
就可以看到顺序不一样了。修改的内容就是把插入的数字先加上2的16次方,然后拿出来之后再减去2的16次方,而已 ^_^
关于HashSet在 java7 与 java8的不同的更多相关文章
- java5、java6、java7、java8的新特性
Java5: 1.泛型 Generics: 引用泛型之后,允许指定集合里元素的类型,免去了强制类型转换,并且能在编译时刻进行类型检查的好处. Parameterized Type作为参数 ...
- ConcurrentHashMap 从Java7 到 Java8的改变
一.关于分段锁 集合框架很大程度减少了java程序员的重复劳动,然而,在Java多线程环境中,以线程安全的方式使用集合类是一个首先考虑的问题. 越来越多的程序员了解到了ConcurrentHashMa ...
- Java7 和 Java8 中的 ConcurrentHashMap 原理解析
Java7 中 ConcurrentHashMap ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些. 整个 ConcurrentHash ...
- java7,java8 中HashMap和ConcurrentHashMap简介
一:Java7 中的HashMap 结构: HashMap 里面是一个数组,然后数组中每个元素是一个单向链表.链表中每个元素称为一个Entry 实例,Entry 包含四个属性:key, value, ...
- java7与java8的新特性
java7 新特性: 1. switch 里面的 case 条件可以使用字符串了. 2. 运用 List\tempList = new ArrayList<>(); 即泛型实例化类型自动判 ...
- Java7与Java8中的HashMap和ConcurrentHashMap知识点总结
JAVA7 Java7的ConcurrentHashMap里有多把锁,每一把锁用于其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率呢.这 ...
- java7和java8新特性
以下来至网址: http://blog.csdn.net/samjustin1/article/details/52268004 Java7 新特性 1.switch中可以使用字符串了 String ...
- java7与java8中计算两个日期间隔多少年多少月多少天的实现方式
最近工作中碰到个新需求,计算每个员工入职公司的时长,要求形式为多少年多少月多少天形式,某个值为0就跳过不显示,因为前段时间学习过java8新特性,对于这个需求,java8的新时间日期API可以直接解决 ...
- 配置java环境变量,实现一条命令自由切java7 或java8
在多个java编译环境中,有时需要java 7,有时又需要java 8,怎么配置java 环境,可以快速自动切换呢?下面用mac演示在 /etc/bashrc 中配置的环境变量 # 设置 JDK ex ...
随机推荐
- mem_fun与mem_fun_ref的区别
一句话:container<ClassType*>就用mem_fun,container<ClassType>就用mem_fun_ref 参考: http://www.cplu ...
- 一款纯css3实现的tab选项卡
今天给大家带来一款纯css3实现的tab选项卡.单击左侧的选项的时候,右侧内容以动画的形式展示.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class=&quo ...
- java Web监听器导图详解
监听器是JAVA Web开发中很重要的内容,其中涉及到的知识,可以参考下面导图: Web监听器 1 什么是web监听器? web监听器是一种Servlet中的特殊的类,它们能帮助开发者监听web中的特 ...
- MDI多文档窗体--在一个窗体中装载多个窗体
创建MDI窗体之前,首先要明确两个概念:父窗体和子窗体,在MDI窗体中,起到容器作用的窗体被称为“父窗体”, 可放在父窗体中的其他窗体被称为子窗体,也成为MDI子窗体.当应用程序启动时,首先会显示父窗 ...
- span和img标签对齐
html代码 <li> <span class="left_item">在线</span> <img class="right_ ...
- jQuery——实现弹窗
window.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...
- Entity Framework(三):使用特性(数据注解)创建表结构
一.理解Code First及其约定和配置 传统设计应用的方式都是由下而上的,即我们习惯优先考虑数据库,然后使用这个以数据为中心的方法在数据之上构建应用程序.这种方法非常适合于数据密集的应用或者数据库 ...
- mongdb 慢查询
查看mongodb慢查询 赶紧打开服务器爸爸,开慢查询,看下耗时500ms以上的都是些啥: db.setProfilingLevel(2,500) 看下最近的10条具体的慢查询指令: db.syste ...
- 【BZOJ】3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛(排列组合+乘法逆元+欧拉定理/费马小定理)
http://www.lydsy.com/JudgeOnline/problem.php?id=3398 以下牡牛为a,牝牛为b. 学完排列计数后试着来写这题,“至少”一词可以给我们提示,我们可以枚举 ...
- ThinkPHP项目笔记之RBAC(权限)下篇
接着谈谈:添加用户以及用户管理列表 e.添加用户