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标签等(代码片段

有人可以解释以下 R 代码片段吗? [关闭]

片段内容未出现在手机上

30 段 Python 实用代码

'numpy.ndarray':对象不可调用错误

即学即用的 30 段 Python 实用代码