- 一个单列集合;
- 不保证set的迭代顺序,特别他不保证该顺序恒久不变;
- 前身是HashTable(哈希表:线程安全);
- 允许使用null元素
- 此时先是不同步的,所以线程不安全。
- HashSet的底层其实是一个HashMap;
- HashSet数据结构:一个对象数组,数组中存有链表;
- HashSet初始容量为16,加载因子为0.75;
- 我们都知道HashMap是一个双列集合,而HashSet是单列集合;
- 当HashSet创建一个HashMap的时候,把HashSet只在HashMap的key一列存值;
- 而HashMap的key值是不可重复的,也就是说HashSet的值是不重复的。
- 由于HashSet的加载因子为0.75,也就是说当HashSet的内存使用率为75%是一个分割线;
- 当内存使用率达到75%,那HashSet集合中的对象数组将进行扩容;
- 这时候HashSet中的 所有元素的顺序将尽数被打乱重新存入到HashSet中。
- 首先每一个对象都有自己的HashCode;
- HashSet将依照这个HashCode对自己的容量进行取余;
- 根据这个余数,HashSet将这个值存入到对应的对象数组“下标”的链表中。
- 而这里又会出现一个小问题4(当两个对象,HashCode不相同,但是内容却完全相同的情况下如何存入HashSet中?数据去重)。
Person p1 = new Person("张三",18); Person p2 = new Person("张三",18); HashSet问题4: 如果存入两个内容完全相同的对象,而HashSet要求我们数值不可重复,那我们 如何去重 ?set = new HashSet (); set.add(p1); set.add(p2);
- 首先我们知道这两个对象虽然内容一样,但是也没有完全一样,因为他们引用的内存空间不是同一块内存空间;
- 所以两个不一样的对象,他们的HashCode也是不一样的(极大概率);
- 这也就意味着,在实体类中没有重写hashCode()和equals()方法的时候,他们都能存到HashSet中,而且不被覆盖;
- 所以我们在 创建实体类的时候要重写hashCode()和equals(),确保两个内容完全相同的对象只能插入一个到HashSet中。
- 什么是内存泄漏?
- 在我们重写了hashCode()和equals()方法之后,对象会根据hashCode()方法,将对象的属性加入到一个算术中计算,得出hashCode;
- 当我们把这个对象存入HashSet后,我们突然要更改这个对象的属性,当然这个时候我们还能找到这个对象并更改其内容;
- 而在我们更改了这个对象的属性之后他的HashCode也会随之改变;
- 当我们再次访问HashSet来查找这个对象的时候,新生成的HashCode会让我们无法找到原来的对象,比如删除该对象就无法删除;
- 这,就是内存泄漏!
- 那我们如何避免?
- 在重写HashCode()方法的时候,把可能之后会有变化的属性去掉,只留下不会进行更改的属性。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)