• 黑马程序员-Java基础之Set接口及HashSet类


    ================ ASP.Net+Android+IOS开发.Net培训、期待与您交流! ================

    前面已经介绍过Set集合,它类似与一个罐子,一旦把对象“丢进”Set集合中,集合里多个对象之间没有明显的顺序。Set集合和Collection基本上完全一样,没有提供任何额外的方法。实际上Set就是Collection,只是行为不同(Set不允许包含重复元素)。

    Set集合不允许包含相同的元素,如果试图把两个相同的元素添加到同一个Set集合中时,添加操作失败,add方法返回false,则新元素不会被添加。

    Set集合判断两个元素相同不是使用==运算符,而是根据equals方法。也就是说,如果两个对象用equals方法比较返回trueSet就不会接受这两个对象,反之则可以接受两个对象(甚至这两对象是同一个对象,Set也可把它们当成两个对象来处理,后面程序可以看到这种极端的情况)。如下是使用普通Set的示例程序代码:

     1 package com.king.testcollection;
     2 
     3  
     4 
     5 import java.util.HashSet;
     6 
     7 import java.util.Set;
     8 
     9  
    10 
    11 public class TestSet {
    12 
    13  
    14 
    15 /**
    16 
    17  * @author 王者黑桃
    18 
    19  */
    20 
    21 public static void main(String[] args) {
    22 
    23 // 定义一个Set集合
    24 
    25 Set names=new HashSet();
    26 
    27 //添加一个字符串对象
    28 
    29 names.add(new String("王者黑桃"));
    30 
    31 //再次添加一个字符串对象
    32 
    33 //因为两次添加的字符串对象通过equals方法比较相等,所以添加失败,返回false
    34 
    35 boolean result=names.add(new String("王者黑桃"));
    36 
    37 System.out.println(result);
    38 
    39 //输出将看到集合中只有一个元素
    40 
    41 System.out.println(names);
    42 
    43  
    44 
    45 }
    46 
    47  
    48 
    49 }

        从上面程序中可以看出,names集合两次添加的字符串对象明显不是同一个对象(因为两次都调用了new关键字来创建字符串对象),这两个字符串对象通过==运算符判断肯定返回false,但它们通过equals方法判断返回true,所以添加失败。最后输出names集合将看到一个元素。

    上面介绍的是Set集合的通用知识,因此完全适用与后面介绍的HashSetTreeSetEnumSet三个实现类,只是三个实现类还各有特色。

    HashSet

    HashSet类是Set接口的典型实现,大多数时候使用Set集合时就是使用这三个实现类。HashSetHash的算法来存储集合中的元素,因此具有很好的存取和查找性能。

    HashSet具有以下特点:

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

    2.HashSet不是同步的,如果多个线程同时访问一个Set集合,如果多个线程同时访问一个HashSet,如果有2个或2个以上线程同时修改了HashSet集合时,必须通过代码保证其同步。

    3.集合元素值可以是NULL

     当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来获取该对象的hashCode值,然后根据hashCode值来决定该对象在HashSet集合中的存储位置。如果两个元素通过equals方法比较返回true,但是它们的hashCode()方法返回值不相等,HashSet将会把它们存放在不同的位置,也就可以添加成功。

    简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较想等,并且两个对象的hashCode()方法的返回值也相等。

    下面程序分别提供了三个类,它们分别重写了equalshashCode两个方法的一个或全部,通过此程序可以更清楚的了解HashSet集合判断两个元素想等的标准。

    实例代码:

     1 package com.king.testcollection;
     2 
     3  
     4 
     5 import java.util.HashSet;
     6 
     7  
     8 
     9 /**
    10 
    11  * @author 王者黑桃
    12 
    13  */
    14 
    15 //类A的equals方法总是返回true,但并没有重写其hashCode()方法
    16 
    17 class A{
    18 
    19 public boolean equals(Object obj){
    20 
    21 return true;
    22 
    23 }
    24 
    25 }
    26 
    27 //类B的hashCode()方法总是返回1,但并没有重写其equals方法
    28 
    29 class B{
    30 
    31 public int hashCode(){
    32 
    33 return 1;
    34 
    35 }
    36 
    37 }
    38 
    39 //类B的hashCode()方法总是返回2,equals方法的返回值true
    40 
    41 class C{
    42 
    43 public int hashCode(){
    44 
    45 return 2;
    46 
    47 }
    48 
    49 public boolean equals(Object obj){
    50 
    51 return true;
    52 
    53 }
    54 
    55 }
    56 
    57 public class TestHashSet {
    58 
    59  
    60 
    61  
    62 
    63 public static void main(String[] args) {
    64 
    65 HashSet names=new HashSet();
    66 
    67 // 分别向names集合中添加三个类的两个对象
    68 
    69 names.add(new A());
    70 
    71 names.add(new A());
    72 
    73 names.add(new B());
    74 
    75 names.add(new B());
    76 
    77 names.add(new C());
    78 
    79 names.add(new C());
    80 
    81 System.out.println(names);
    82 
    83  
    84 
    85 }
    86 
    87  
    88 
    89 }

    上面程序中names集合中分别添加了2A对象、2B对象和2C对象,其中C类重写的equals()方法总是返回truehashCode()总是返回2,这将导致HashSet将会把2C对象当成同一个对象。运行程序将看到如下结果:

    [com.king.testcollection.B@1, com.king.testcollection.B@1, com.king.testcollection.C@2, com.king.testcollection.A@6d4b473, com.king.testcollection.A@456d3d51]

    这里有个问题需要注意:如果需要把一个对象放入HashSet集合中时,如果重写了equals()方法时,也应该重写其hashCode()方法,其规则是:如果两个对象通过equals()方法比较返回true时,这两个hashCode也应该相同。

    如果两个对象通过quals()方法比较返回true,但这两个对象的hashCode()方法返回不同的hashCode时,这将导致HashSet会把这两个对象保存在HashSet的不同位置,从而这两个对象都将添加成功,这与Set集合的规则有点出入。

    如果两个对象的hashCode()方法返回的hashCode相同,但它们通过equals()方法比较返回False时,这将更麻烦:因为两个对象的hashCode值相同,HashSet将试图把它们保存在同一位置,但实际上又不行(否则将只剩下一个对象),所以处理起来比较麻烦;而且HashSet访问集合元素时也是根据元素的hashCode值来访问的,如果HashSet中包含两个元素有相同的hashCode值,将导致性能下降。

    HashSet中每个能存储元素的“槽位”通常别称为“桶”,如果有多个hashCode的值相同,但它们通过equals()方法比较返回False,就需要在一个“桶”里放多个元素,从而导致性能下降。

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

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

    2.对象中用作equals比较标准的属性,都应该用来计算hashCode值。

     HashSet还有一个子类LinkedHashSetLinkedHashSet集合也是根据元素hashCode值来决定元素的存储位置,但他同时使用链表维护元素的次序,这样使的元素看起来是以插入的顺序保存的。也就是说当遍历LinkedHashSet集合里元素时,HashSet将会按元素的添加顺序来访问集合里的元素。

    ================ASP.Net+Android+IOS开发.Net培训、期待与您交流! ================ 详细请查看:http://edu.csdn.net

     

  • 相关阅读:
    Spring Bean Scope 有状态的Bean 无状态的Bean
    管理Mysql常用指令
    mysql处理特殊字符
    linux下memcached安装 和redis安装,jdk,tomcat,mysql 安装
    Jenkins
    tomcat站点配置
    tomcat配置jdbc
    spring 深入reading
    JAVA随机数之多种方法从给定范围内随机N个不重复数
    Intellij IDEA 快捷键整理
  • 原文地址:https://www.cnblogs.com/super614508584/p/3508368.html
Copyright © 2020-2023  润新知