Java基础内容分享,hashset取值详解

Java基础内容分享,hashset取值详解

深圳达内教育      2022-04-16 19:21:01     6

Java基础内容分享,hashset取值详解,对于HashSet而言,它是基于HashMap实现的,HashSet底层采用HashMap来保存所有元素,因此HashSet的实现比较简单,查看HashSet的源

课程价格 请咨询

上课时段: 授课校区:

详细介绍

对于HashSet而言,它是基于HashMap实现的,HashSet底层采用HashMap来保存所有元素,因此HashSet的实现比较简单,查看HashSet的源代码,可以看到如下代码:

public class HashSet<E>    extends AbstractSet<E>    implements Set<E>, Cloneable, java.io.Serializable   {    // 使用 HashMap 的 key 保存 HashSet 中所有元素   private transient HashMap<E,Object> map;    // 定义一个虚拟的 Object 对象作为 HashMap 的 value    private static final Object PRESENT = new Object();    ...    // 初始化 HashSet,底层会初始化一个 HashMap    public HashSet()    {        map = new HashMap<E,Object>();    }    // 以指定的 initialCapacity、loadFactor 创建 HashSet    // 其实就是以相应的参数创建 HashMap    public HashSet(int initialCapacity, float loadFactor)    {        map = new HashMap<E,Object>(initialCapacity, loadFactor);    }    public HashSet(int initialCapacity)    {        map = new HashMap<E,Object>(initialCapacity);    }    HashSet(int initialCapacity, float loadFactor, boolean dummy)    {        map = new linkedHashMap<E,Object>(initialCapacity            , loadFactor);    }    // 调用 map 的 keySet 来返回所有的 key    public Iterator<E> iterator()    {        return map.keySet().iterator();    }    // 调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 Set 里元素的个数   public int size()    {        return map.size();    }    // 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空,   // 当 HashMap 为空时,对应的 HashSet 也为空   public boolean isEmpty()    {        return map.isEmpty();    }    // 调用 HashMap 的 containsKey 判断是否包含指定 key    //HashSet 的所有元素就是通过 HashMap 的 key 来保存的   public boolean contains(Object o)    {        return map.containsKey(o);    }    // 将指定元素放入 HashSet 中,也就是将该元素作为 key 放入 HashMap    public boolean add(E e)    {        return map.put(e, PRESENT) == null;    }    // 调用 HashMap 的 remove 方法删除指定 Entry,也就删除了 HashSet 中对应的元素   public boolean remove(Object o)    {        return map.remove(o)==PRESENT;    }    // 调用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素   public void clear()    {        map.clear();    }    ...   }

由上面源程序可以看出,HashSet的实现其实非常简单,它只是封装了一个HashMap对象来存储所有的集合元素,所有放入HashSet中的集合元素实际上由HashMap的key来保存,而HashMap的value则存储了一个PRESENT,它是一个静态的Object对象。

HashSet的绝大部分方法都是通过调用HashMap的方法来实现的,因此HashSet和HashMap两个集合在实现本质上是相同的。

掌握上面理论知识之后,接下来看一个示例程序,测试一下自己是否真正掌握了HashMap和HashSet集合的功能。

 class Name  {      private String first;       private String last;             public Name(String first, String last)       {           this.first = first;           this.last = last;       }         public boolean equals(Object o)       {           if (this == o)           {               return true;           }                 if (o.getClass() == Name.class)           {               Name n = (Name)o;               return n.first.equals(first)                   && n.last.equals(last);           }           return false;       }   }    public class HashSetTest  {      public static void main(String[] args)      {           Set<Name> s = new HashSet<Name>();          s.add(new Name("abc", "123"));          System.out.println(              s.contains(new Name("abc", "123")));      }  }

上面程序中向HashSet里添加了一个new Name("abc","123")对象之后,立即通过程序判断该HashSet是否包含一个new Name("abc","123")对象。粗看上去,很容易以为该程序会输出true。

实际运行上面程序将看到程序输出false,这是因为HashSet判断两个对象相等的标准除了要求通过equals()方法比较返回true之外,还要求两个对象的hashCode()返回值相等。而上面程序没有重写Name类的hashCode()方法,两个Name对象的hashCode()返回值并不相同,因此HashSet会把它们当成2个对象处理,因此程序返回false。

由此可见,当我们试图把某个类的对象当成HashMap的key,或试图将这个类的对象放入HashSet中保存时,重写该类的equals(Object obj)方法和hashCode()方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的hashCode()返回值相同时,它们通过equals()方法比较也应该返回true。通常来说,所有参与计算hashCode()返回值的关键属性,都应该用于作为equals()比较的标准。

如下程序就正确重写了Name类的hashCode()和equals()方法,程序如下:

class Name   {       private String first;      private String last;      public Name(String first, String last)      {           this.first = first;           this.last = last;       }       // 根据 first 判断两个 Name 是否相等      public boolean equals(Object o)       {           if (this == o)           {               return true;           }           if (o.getClass() == Name.class)           {               Name n = (Name)o;               return n.first.equals(first);           }           return false;       }              // 根据 first 计算 Name 对象的 hashCode() 返回值      public int hashCode()       {           return first.hashCode();       }        public String toString()       {           return "Name[first=" + first + ", last=" + last + "]";       }    }       public class HashSetTest2    {       public static void main(String[] args)       {           HashSet<Name> set = new HashSet<Name>();           set.add(new Name("abc" , "123"));           set.add(new Name("abc" , "456"));           System.out.println(set);       }   }

上面程序中提供了一个Name类,该Name类重写了equals()和toString()两个方法,这两个方法都是根据Name类的first实例变量来判断的,当两个Name对象的first实例变量相等时,这两个Name对象的hashCode()返回值也相同,通过equals()比较也会返回true。

程序主方法先将第一个Name对象添加到HashSet中,该Name对象的first实例变量值为"abc",接着程序再次试图将一个first为"abc"的Name对象添加到HashSet中,很明显,此时没法将新的Name对象添加到该HashSet中,因为此处试图添加的Name对象的first也是"abc",HashSet会判断此处新增的Name对象与原有的Name对象相同,因此无法添加进入,程序在①号代码处输出set集合时将看到该集合里只包含一个Name对象,就是第一个、last为"123"的Name对象。

以上就是深圳达内教育java培训机构的小编针对“Java基础内容分享,hashset取值详解”的内容进行的回答,希望对大家有所帮助,如有疑问,请在线咨询,有专业老师随时为你服务。

培训啦提醒您:交易时请核实对方资质,对于过大宣传或承诺需谨慎!任何要求预付定金、汇款等方式均存在风险,谨防上当。