从JDK源码学习HashSet和HashTable
HashSet
Java中的集合(Collection)有三类,一类是List,一类是Queue,再有一类就是Set。 前两个集合内的元素是有序的,元素可以重复;最后一个集合内的元素无序,但元素不可重复。
Set:
1.用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复
2.对象的相等性本质是对象hashCode值(java是依据对象的内存地址计算出的此序号,不同对象的hashcode不一定不一样)判断的,如果想要让两个不同的对象视为相等的,就必须覆盖Object的hashCode方法和equals方法,比如string类就重写了hashcode方法,算出的hashcode值并不是对象的实际内存地址,equals也被重写了
String.hashcode()
String.equals
1.先验证是否是否是同一个对象
2.再验证是否是同一类型(String),然后验证值是否相等
Hashset也是支持序列化、浅拷贝的
Hashset内部还是Hashset,只不过调用它的add直接放入的不再是键值对
看下其add方法:
直接调用map.put放入e所代表的的键以及present成员变量
而这里的map就是hashset内部存储值的结构,可以看到其键是放入的,键所对应的值是object的实例
既然其用的hashmap,那么其构造方法实际上就是定义hashmap,所以就是hashmap的那四种构造方法
那么取值的时候不像hashmap那么方便可以直接取某个键对应的值,取hashset中的值是获得一个迭代器,取得内部hashmap所有的键然后遍历再进行操作
所以其内部存储时结构也和hashmap结构一样了,同时hashset也是非线程安全的
ArrayList和HashSet的区别
1.前者有序,可存放重复值,后者无序,不可存放重复值,因为hashmap键不能重复
2.Arraylist被填满扩充1.5倍,Hashset扩充机制和hashmap相同
HashTable
HashTable实现的map接口,支持序列化和浅拷贝
hashtable也是"拉链法"实现的hash表(只是数组加单链表),其内部存储结构为entry数组,和hashmap类似,其也有负载因子和初始容量
其构造方法也有4种
第一种如下支持初始指定容量和负载因子,此时将给entry分配内存空间,并且初始化阈值为初始容量和(2的31次-1)-8(最大值字节数)+1的较小值
第二种只指定初始化大小
第三种使用默认初始容量和负载因子,初始容量为11
第四种则是直接放入一个map进来初始化构造一个hashtable,此时的hashtable容量将变为放入的map的键值对的个数的2倍和默认容量的较大值,然后再将map放入
而hashmap这里是和hashtable不一样的,初始化时将用放入的map的键值数量/负载因子+0.75,算出的值再和2的30次方做比较,取两者较小值和阈值进行比较,并赋值阈值为大于算出值最接近的2的次方值,便于后面resize扩容,然后后面再通过循坏将map中的值依次放入
HashTable和HashMap的比较
1.HashTable 基于 Dictionary 类,而 HashMap 是基于 AbstractMap。Dictionary 是任何可将键映射到相应值的类的抽象父类, AbstractMap 是基于 Map 接口的实现,但hashtable和hashmap二者都实现了Map接口
2.hashmap可以放键和值均为null的值,但是这样的值你也只能放一个进去,所以hashmap中判断是否存在某个键要用containskey(键必定是唯一的),而不能用get,因此能有多个键对应的value都是null,而hashtable的键和值不可以为null,否则将会报空指针错误
hashmap的处理:
所以hashmap考虑到了这种key为null的情况,让其hash算出来为0,不为null的key再调用object的hashcode方法算hash
hashmap的get方法如下图,不存在也有可能返回null或者键的值为null,无法判断
hashtable的处理:
hashtable的设计并没有考虑这么多,而是直接调用其key的hashcode,那么null.hashcode,必将报错
hashtable将检测放入的键对应的值是否为null
3.hashmap在默认情况下是非线程安全的,而hashtable以为基本public方法都是用synchronized修饰的,因此其为同步的
4.两者的扩容方式不一样,hashmap扩容是resize方法,容量变为old*2,而hashtable是rehash方法,容量变为old*2+1,
5.两者内部遍历实现不一样:
hashmap的键值遍历为iterator
hashtable的键值遍历为Enumerator
6.获取键所在的位置时的方法不同:
hashmap中首先用与逻辑代替了模运算加快了速度,2的n次方-1位全1二进制位再与key的hash与算出键值对的位置,并且其hash值并不是单纯的hashcode,而是用到了key的hashcode的高16位来做异或运算
hashtable中是根据key直接算一个hashcode(可能为负值),然后再和2的31次方-1做与算出来的正值再模当前hash表的长度,然后确定键值对的位置,那么取模的效率肯定没有与逻辑的运行效率更高
参考
https://blog.csdn.net/fujiakai/article/details/51585767 hashmap和hashtable区别
https://wiki.jikexueyuan.com/project/java-collection/hashtable.html hashmap实现原理
从JDK源码学习HashSet和HashTable的更多相关文章
- JDK源码学习--String篇(二) 关于String采用final修饰的思考
JDK源码学习String篇中,有一处错误,String类用final[不能被改变的]修饰,而我却写成静态的,感谢CTO-淼淼的指正. 风一样的码农提出的String为何采用final的设计,阅读JD ...
- JDK源码学习系列05----LinkedList
JDK源码学习系列05----LinkedList 1.LinkedList简介 LinkedList是基于双向链表实 ...
- JDK源码学习系列04----ArrayList
JDK源码学习系列04----ArrayList 1. ...
- JDK源码学习系列03----StringBuffer+StringBuilder
JDK源码学习系列03----StringBuffer+StringBuilder 由于前面学习了StringBuffer和StringBuilder的父类A ...
- JDK源码学习系列02----AbstractStringBuilder
JDK源码学习系列02----AbstractStringBuilder 因为看StringBuffer 和 StringBuilder 的源码时发现两者都继承了AbstractStringBuil ...
- JDK源码学习系列01----String
JDK源码学习系列01----String 写在最前面: 这是我JDK源码学习系列的第一篇博文,我知道 ...
- JDK源码学习笔记——LinkedHashMap
HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...
- JDK源码学习笔记——String
1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() { ...
- JDK源码学习笔记——Integer
一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...
随机推荐
- PBM error occurred during PreCloneCheckCallback: 由于目标计算机积极拒绝,无法连接
问题如下: 迁移存储和主机的时候发生错误,错误如下: 出现了常规系统错误: PBM error occurred during PreCloneCheckCallback: 由于目标计算机积极拒绝,无 ...
- 谈谈SQL优化
写SQL是学习数据库必须掌握的非常重要的技能之一.在学习过程当中,我们会尝试写各种各样满足需求的SQL语句.在实际项目中,优秀的SQL语句和普通的SQL语句的执行速度差别非常大.对于一个数据量很大的系 ...
- 后端程序员必备:书写高质量SQL的30条建议
前言 本文将结合实例demo,阐述30条有关于优化SQL的建议,多数是实际开发中总结出来的,希望对大家有帮助. 1.查询SQL尽量不要使用select *,而是select具体字段. 反例子: sel ...
- Python异常处理,将异常写入到一个文件
'''定义一个函数func(urllist) urllist:为URL的列表,例如:['http://xx.com','http://www.xx.com','http://www.xxx.com'. ...
- 关于MySQL 建表的一些建议
由于在生产环境下,我们对MySQL数据库的操作通常是通过命令行进行操作,因此,建议建表的时候也手写MySQL语句(不建议用图形界面建表). 1.添加注释的格式 在编写MySQL语句时,我们通常会被要求 ...
- vue one
目录 复习 Vue框架 Vue的优点 Vue的使用 vue完成简单的事件 vue操作简单样式 小结 指令 文本指令 事件指令 属性指令 条件指令 复习 """ 1.BBS ...
- 修改imx6ull开机LOGO(一)
imx6ull启动的时候默认显示uboot自带的开机画面,按照如下步骤修改为我们想要的开机画面,如下: 首先去掉液晶屏右上角的打印信息 修改/drivers/video/cfb_console.c ...
- leetcode 945. 使数组唯一的最小增量
题目 给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1. 返回使 A 中的每个值都是唯一的最少操作次数. 示例 1: 输入:[1,2,2] 输出:1 解释:经过一次 mov ...
- Mysql性能优化:什么是索引下推?
导读 索引下推(index condition pushdown )简称ICP,在Mysql5.6的版本上推出,用于优化查询. 在不使用ICP的情况下,在使用非主键索引(又叫普通索引或者二级索引)进行 ...
- Web Scraping(网页抓取)基本原理 - 白话篇
本文主要介绍 Web Scraping 的基本原理,基于Python语言,大白话,面向可爱的小白(^-^). 易混淆的名称: 很多时候,大家会把,在网上获取Data的代码,统称为"爬虫&qu ...