zoukankan      html  css  js  c++  java
  • Java——(三)Collection之Set集合、HashSet类

    ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

    一、Set集合

      Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加

    操作失败,add方法返回false,而新元素不会被加入。

      Set判断两对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用

    equals方法比较返回true,Ser就不会接受这两个对象;反之,只要两个对象用equals方法比较

    返回false,SEt就会接受这两个对象(甚至这两个对象是同一个对象,Set也可把它们当成两个对

    象出来)。下面是使用普通Set的示例程序。

     1 import java.util.HashSet;
     2 import java.util.Set;
     3 
     4 
     5 public class SetTest {
     6 
     7     public static void main(String[] args) {
     8         Set names = new HashSet<>();
     9         //添加一个字符串对象
    10         names.add(new String("暨雪"));
    11         //再次添加一个字符串对象
    12         //因为两个字符串对象通过equals方法比较相等
    13         //所以添加失败,返回false
    14         boolean reasult = names.add(new String("暨雪"));
    15         //从下面输出看到集合只有一个元素
    16         System.out.println(reasult + "-->" + names);
    17     }
    18 
    19 }

    运行结果:

    false-->[暨雪]

      从上面程序中可以看出,names集合两次添加的字符串对象明显不是同一对象(因为两次都调

    用了new关键字来创建字符串对象),这两个字符串对象使用==运算符判断肯定返回false,但通过

    equals方法比较将返回true,所以添加失败。最后结果输出只有一个元素。

     1.HashSet类

    HashSet是Set接口的典型实现,大多数时候使用Set集合是就是使用这个实现类。HashSet按Hash

    算法来存储集合中的元素,因此具有很好的存取和查找性能。

      HashSet具有以下特点:

      1)不能保证元素的排序顺序,顺序有可能发生变化。

      2)HashSet不是同步的,如果多线程同时访问一个HashSet,假设有两个或两个以上线程同时

    修改了HashSet集合时,则必须通过代码来保证其同步。

      3)集合元素值可以是null。

      HashSet集合判断两个以上相等的标准是两个对象通过equals()方法比较相等,并且两个对象的

    hashCode()方法返回值也相等。

    下面程序分别提供了三个类A、B和C,它们分别重写了equals()、hashCode()两个方法的一个或全部

    ,通过此程序可以看到HashSet判断集合元素相同的标准。

     1 import java.util.HashSet;
     2 
     3 
     4 public class HashSetTest {
     5     //类A的equals方法总是返回true,但没有重写hashCode方法
     6     static class A {
     7         @Override
     8         public boolean equals(Object o) {
     9             return true;
    10         }
    11     }
    12     //类B的hashCode总是返回1,但没有重写equals方法
    13     static class B {
    14         @Override
    15         public int hashCode() {
    16             return 1;
    17         }
    18     }
    19     //类C重写了hashCode方法和equals方法
    20     static class C {
    21         @Override
    22         public int hashCode() {
    23             return 2;
    24         }
    25         @Override
    26         public boolean equals(Object obj) {
    27             return true;
    28         }
    29     }
    30 
    31     public static void main(String[] args) {
    32 
    33         HashSet names = new HashSet<>();
    34         names.add(new A());
    35         names.add(new A());
    36         names.add(new B());
    37         names.add(new B());
    38         names.add(new C());
    39         names.add(new C());
    40         
    41         System.out.println(names);
    42     }
    43 
    44 }

    运行结果:

    [HashSetTest$B@1, HashSetTest$B@1, HashSetTest$C@2, HashSetTest$A@7e5284e9, HashSetTest$A@12720f6c]

    从上面程序可以看出,即使两个A对象通过equals()方法比较返回true,但HashSet依然把它们当成

    两个对象;即使两个B对象的hashCode()返回相同值(都是1),但HashSet依然把它们当成同一个

    对象。

    注意:

     当把一个对象放入HashSet中时,如果需要重写该方法对应类的equals()方法,则也应该重写

    hashCode()方法。其规则是:如果两个对象通过equals()方法比较返回true,这两个对象的hashCode

    ()值也应该相同。

      重写hashCode()方法的基本规则:

      1)在程序运行中,同一对象多次调用hashCode()方法应该返回相同的值。

      2)当两个对象通过equals()方法比较返回true时,这两个对象的hashCode()方法应返回相等的值。

      3)对象中用作equals()方法比较标准的Filed,都应该用计算hashCode值。

    hashCode返回值的计算:

    return f1.hashCode() + (int) f2;

    为了避免直接相加产生偶然相等(两个对象f1、f2Field并不相等,但他们的和恰好相等),

    可以通过为个Field乘以任意一个质数后在相加。

    return f1.hashCode() * 17 + (int) f2 * 13;

       如果向HashSet中添加一个可变对象后,后面出现修改了该可变对象的Field,则可能导致

    它与集合中的其他元素相同(即两个对象通过equals()方法比较返回true,两个对象的

    hashCode()值也相等)。这就有可能导致HashSet中包含两个相同的对象。下面程序演示了这

    种情况。

     1 import java.util.HashSet;
     2 import java.util.Iterator;
     3 
     4 class R {
     5     int count;
     6     public R (int count){
     7         this.count = count;
     8     }
     9     @Override
    10     public String toString() {
    11         
    12         return "R[count:" + count + "]";
    13     }
    14     @Override
    15     public boolean equals(Object obj) {
    16         
    17         if (this == obj) {
    18             return true;
    19         }
    20         if (obj != null && obj.getClass() == R.class) {
    21             R r = (R) obj;
    22             if (r.count == this.count) {
    23                 return true;
    24             }
    25         }
    26         return false;
    27     }
    28     @Override
    29     public int hashCode() {
    30         
    31         return this.count;
    32     }
    33 }
    34 public class HashSetTest2 {
    35 
    36     public static void main(String[] args) {
    37 
    38         HashSet hs = new HashSet<>();
    39         hs.add(new R(5));
    40         hs.add(new R(-3));
    41         hs.add(new R(9));
    42         hs.add(new R(-2));
    43         //打印HashSet集合,集合没有重复
    44         System.out.println(hs);
    45         //取出第一个元素
    46         Iterator it = hs.iterator();
    47         R first = (R) it.next();
    48         //为第一个元素的count实例变量赋值
    49         first.count = -3;
    50         //再次输出HashSet集合,集合元素有重复元素
    51         System.out.println(hs);
    52         //删除count为-3的R对象
    53         hs.remove(new R(-3));
    54         System.out.println(hs);
    55         System.out.println("hs是否包count为-3的R对象?" + hs.contains(new R(-3)));
    56         System.out.println("hs是否包count为5的R对象?" + hs.contains(new R(5)));
    57         System.out.println("hs是否包count为9的R对象?" + hs.contains(new R(9)));
    58     }
    59 
    60 }

    运行结果:

    [R[count:5], R[count:9], R[count:-3], R[count:-2]]
    [R[count:-3], R[count:9], R[count:-3], R[count:-2]]
    [R[count:-3], R[count:9], R[count:-2]]
    hs是否包count为-3的R对象?false
    hs是否包count为5的R对象?false
    hs是否包count为9的R对象?true

      上面程序中的first.count = -3;因为改变了HashSet集合中第一个R对象的count实例变量

    的值,这将导致该R对象与集合中的其他对象相同。当试图删除count = -3的R对象时,HashSet

    会计算出该对象的hashCode值,从而找出该对象在集合中保存位置,然后把此处的对象与count

    为-3的R对象通过equals()方法进行比较,如果相等则删除该对象——HashSet只有第三元素才

    满足该条件(第一个元素实际上保存在count为5的R对象对应的位置),所以第三个元素被删除

    。至于第一个count为-3的R对象,它保存在count为5的R对象对应的位置,但是用equals()方法

    拿它和count为5的R对象比较时有返回false——这将导致HashSet不可能准确访问该元素。

      

  • 相关阅读:
    测试种类
    Android ADB使用之详细篇
    Maven 生命周期
    在Eclipse中新建Maven项目
    Maven搭建环境(Linux& Windows)
    一个简单的JUnit项目
    Assertions
    Aggregating tests in suites
    Test execution order
    c#一个分页控件的例子
  • 原文地址:https://www.cnblogs.com/xiongxuesong/p/4563177.html
Copyright © 2011-2022 走看看