Set
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Set相关的知识,希望对你有一定的参考价值。
Set : 元素不可相等,不维持有序. 和Collection基本相同,没提供额外的方法. HashSet TreeSet EnumSet
如何判断两个元素相等? 理论上成员变量全相等,即可认为相等. 除了HashSet,其他Set添加元素时,将待添加元素与已存元素equals,true丢弃,false加入.
但是HashSet例外!这是因为HashSet添加新元素的方式迥异.
HashSet添加新元素 : 先根据元素的hashCode计算出存储位置,如果计算出的存储位置已经有元素,可能已经存入相等元素,也有可能不相等元素但是hashCode相同的元素加入了,如果此时草率的丢弃新元素,可能造成其实元素没加入过,但是永远无法加入容器. 所以再equals一下,如果是true,说明确实是前者原因,就丢弃,如果是后者,HashSet采取的措施是继续加入(链后面).
所以对Hash来说,元素相等意味着:不仅equals,hashCode也要相等.
HashSet
要想保证Set的性质 : 元素不相等,必须保证:equals相等,hashCode也相等(这条必须要100%保证,所以hashCode的因子要包全所有的equals成员. 而且元素一旦放入HashSet,不准修改成员变量,要是修改了,查找的时候,你就懵逼了:比如,你存的3,改成-2,找3的时候,根据3hashcode找到的存储位置是个-2,你说咋整?或者你干脆把存-2修改成3,容器就有两个3了,与Set性质相悖)
equals不相等,hashCode也不相等(无法避免的相等也可以,但是会造成性能下降,所以应该全力保证不相等)
综上: 含有Hash二字的容器,相等意味着 equals 和 hascode都相等(根据equals生成hascode) , 在其他非hash容器,相等意味着equals就OK, 但是为了通用性,最好equals和hashcode一起重写!
测试代码,hash容器居然存储了两个equals的元素,还有两个元素的hashcode相等,如下:
1 import java.util.*; 2 public class TestJava { 3 public static void main(String[] args) { 4 A a1 = new A(1,10); A a2 = new A(1,-10); 5 A a3 = new A(2,0); A a4 = new A(3,0); 6 Collection c = new HashSet(); 7 c.add(a1); c.add(a2); c.add(a3); c.add(a4); 8 System.out.println(c); 9 Iterator it = c.iterator(); 10 while(it.hasNext()) { 11 A var = (A)it.next(); 12 System.out.print(var.flag); 13 System.out.println(); 14 } 15 16 System.out.println(c.contains(a2)); 17 } 18 } 19 20 class A { 21 int flag; 22 int dangerous; 23 public A(int flag,int dangerous) { 24 this.flag = flag; 25 this.dangerous = dangerous; 26 } 27 public boolean equals(Object obj) { 28 if(this == obj) 29 return true; 30 if(obj!=null && obj.getClass() == A.class) { 31 A a = (A)obj; 32 if(a.flag == this.flag) 33 return true; 34 } 35 return false; 36 } 37 38 public int hashCode() { 39 return dangerous; 40 } 41 } 42 输出结果: 43 [[email protected], [email protected], [email protected], [email protected]] 44 2 45 3 46 1 47 1 48 true
hashCode的计算方法:
LinkedHashSet是HashSet的子类,几乎和HashSet没差别,只是多出:
遍历LinkedHashSet,输出顺序和添加顺序一致,因为LinkedHashSet维护内部顺序,所以性能略逊于HashSet,
但是用迭代器遍历,速度比HashSet快.
LinkedHashSet怎样维护内部添加顺序的?
很好办,思考静态链表,哈哈哈. 根据哈希函数找到存储位置后,把这个位置填入上次添加的元素的next位置.
以上是关于Set的主要内容,如果未能解决你的问题,请参考以下文章
[原创]java WEB学习笔记61:Struts2学习之路--通用标签 property,uri,param,set,push,if-else,itertor,sort,date,a标签等(代码片段