zoukankan      html  css  js  c++  java
  • 黑马程序员-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

     

  • 相关阅读:
    LeetCode 515. 在每个树行中找最大值(Find Largest Value in Each Tree Row)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 1022. 从根到叶的二进制数之和(Sum of Root To Leaf Binary Numbers)
    LeetCode 897. 递增顺序查找树(Increasing Order Search Tree)
    LeetCode 617. 合并二叉树(Merge Two Binary Trees)
    LeetCode 206. 反转链表(Reverse Linked List) 16
    LeetCode 104. 二叉树的最大深度(Maximum Depth of Binary Tree)
    LeetCode 110. 平衡二叉树(Balanced Binary Tree) 15
    LeetCode 108. 将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree) 14
  • 原文地址:https://www.cnblogs.com/super614508584/p/3508368.html
Copyright © 2011-2022 走看看