HashSet是如何保证不重复的?
HashSet中元素不重复,在向HashSet中add()元素时候,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较。
HashSet中的 add ()方法会使用HashMap 的 add ()方法。而HashMap 的 key 是唯一的,由上面的代码可以看出 HashSet添加进去的值就是作为 HashMap的key。所以不会重复( HashMap比较key是否相等是先比较 hashcode在比较 equals )。
HashMap为什么不是线程安全的?
HashMap为什么不是线程安全的?
假如现在有两个线程A和B,都进行相同的操作(插入数据),而且这两个不同的数据经过哈希算法得到的两个哈希值是相等的,按理说这两个线程都会进入同一个位置,但是会有这样的情况,假使线程A拿着哈希值通过了if判断,就当要进入对应位置时,此时CPU把资源给了线程B,线程B通过了if判断,将数据存储到了对应位置,此时轮到线程A执行,由于线程A之前已经通过了if判断,所以会直接在对应位置插入数据,这时候,线程A就会把线程B的数据给覆盖了,此时就发生了线程不安全的情况。
虽然在HashMap中,发生哈希冲突是可以用链表或者红黑树来解决的,但是在多线程中,可能就直接覆盖了。
HashMap的扩容过程
当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值(当前数组长度*加载因子的值),就要自动扩容。
扩容就是重新计算容量,向HashMap对象里不断添加元素,当HashMap对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。
当然 Java 里的数组是无法自动扩容的,方法 是使用一个新的数组代替已有的容量小的数组。
HashMap hashMap=new HashMap(c);
如果c是2的n次方,则容量为c,否则为大于c的第一个2的n次方的数。
例如:
cap =3, hashMap 的容量为4;
cap =4, hashMap 的容量为4;
cap =5, hashMap 的容量为8;
cap =9, hashMap 的容量为16;
jdk1.7和1.8中HashMap的区别?1.8做了什么优化?
- 在jdk1.7及之前的版本中,HashMap又叫做散列表,是基于一个数组以及多个链表的实现,在哈希冲突的时候,就将对应节点以链表的形式存储。
- 在1.8之后,在发生哈希冲突时,当链表节点数大于8时,就不再以链表形式存储了,就会转化成红黑树。
jdk1.7中:
- 使用一个Entry数组来存储数据,用key的hashcode取模来决定key会被放到数组里的位置,如果hashcode相同,或者haashcode取模后的结果相同(hash collision),那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表。
- 在hashcode 特别差的情况下,比方说所有key的 hashcode 都相同,这个链表可能会很长
jdk1.8中:
使用Node数组来存储数据,但这个Node可能是链表结构,也可能是红黑树结构
- 如果插入的key的hashcode相同,这些key还是会定位到相同的位置
- 同一个位置的key值不超过8个,就是链表结构
- 如果超过了8个,就会调用treeifybin函数转换为红黑树
是真正想要利用JDK1.8的好处,有一个限制:key的对象,必须正确的实现了Compare 接口,如果没有实现Compare接口,或者实现得不正确(比方说所有Compare方法都返回0),那JDK1.8的HashMap其实还是慢于JDK1.7的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。