HashSet

HashSet基与HashMap

源码

 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的add()方法添加集合元素时实际转变为HashMap的put方法来添加key-value对,当新放入的HashSet的Entry中的key相同时(hashCode()的返回值相同,通过equal比较也返回true)时,新添加的Entry的value将value将覆盖原来的Entry的value,但key不会有任何改变,因此,如果向HashSet中添加一个已经存在的元素,新添加的集合元素不会覆盖已经有的集合元素。

package example;

import java.util.HashSet;
import java.util.Set;

class Base{
    private String name;
    private int age;
    public Base(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    
    /*public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }*/
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Base other = (Base) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    @Override
    public String toString() {
        return name+age+"";
    }
    
}

public class Test  {

    public static void main(String[] args) {
        Set<Base> s=new HashSet<Base>();
        s.add(new Base("zhangsan",4));
        System.out.println(s.contains(new Base("zhangsan",4))); //打印false
    }

    

}

打印false的原因,HashSet判断两个对象相等的标准除了要求通过equals()方法比较返回true之外,还要

两个对象的hashCode()返回值相等。因为上面类没有重写hashCode所以HashSet会把它当做两个对象。

原文地址:https://www.cnblogs.com/xurui1995/p/5330796.html