Java容器源码(六)——HashSet源码分析(基于JDK8)

文章目录

    • (一)、概述
    • (二)、类名
    • (三)、成员变量
    • (四)、构造方法
    • (五)、add方法
    • (六)、remove方法
    • (七)、hashCode()与equals()

更多Java容器源码分析可以参考:Java容器源码分析系列(持续更新中!)

(一)、概述

  1. HashSet是Java中常用的一个集合类,是Set接口的一个实现类,而Set接口又继承自Collection接口,所以HashSet同时也是Collection的实现类
  2. HashSet的底层实现是基于HashMap的,它利用HashMap中的key存储数据,使用成员变量PRESENT来填充value。
  3. 因为HashSet的方法非常少,主要都是基于HashMap实现的,如果对HashMap不了解,可以看一下:Java容器源码(五)——HashMap源码分析(基于JDK8)

(二)、类名

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
  1. HashSet继承自AbstractSet,同时实现了Set接口,Cloneable接口,Serializable接口
  2. AbstractSet:实现了Set接口。这样可以让HashSet只需要实现自己额外需要的方法,而不需要重复实现Map接口中的方法,实现了代码的复用。
  3. Map接口:这里只是起到一个标志作用,因为AbstractSet中已经实现过Set接口中的方法了。
  4. Cloneable接口:这里主要实现了浅克隆的功能。
  5. Serializable接口:这里主要是实现了序列化的功能。

(三)、成员变量

	//用来存储数据的成员变量map,其实只使用它的key,value都用PRESENT来填充
    private transient HashMap<E,Object> map;
    // value的填充值,因为只需要HashMap的key
    private static final Object PRESENT = new Object();
  1. HashSet中使用HashMap中的key来存储数据

(四)、构造方法

 	/**
     * 无参构造方法,只是简单地创建一个HashMap
     */
    public HashSet() {
        map = new HashMap<>();
    }

    /**
     * Collection为参数的构造方法
     */
    public HashSet(Collection<? extends E> c) {
    	//根据传入的Collection的大小,对HashMap传入参数,创建HashMap
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        //往HashMap中添加所有元素
        addAll(c);
    }

    /**
     *  传入HashMap的初始容量以及负载因子
     */
    public HashSet(int initialCapacity, float loadFactor) {
    	//将初始容量和负载因子作为参数创建HashMap
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    /**
     * 根据传入的初始容量创建HashMap
     */
    public HashSet(int initialCapacity) {
    	//将初始容量作为参数创建HashMap
        map = new HashMap<>(initialCapacity);
    }

    /**
     *  根据传入的参数创建LinkedHashMap
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    	//根据传入的初始容量,负载因子创建LinkedHashMap
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
  1. 四个构造方法根据参数的不同创建不同的HashMap,进行初始化

(五)、add方法

 public boolean add(E e) {
 		//将传入的元素e存入HashMap中
        return map.put(e, PRESENT)==null;
    }
  1. 如果返回false,代表HashSet中已经有这个元素了。返回true的话表示添加成功。

(六)、remove方法

public boolean remove(Object o) {
		//将元素从HashMap中删除
        return map.remove(o)==PRESENT;
    }
  1. 如果返回PRESENT,则代表删除成功,如果返回null,代表删除失败

(七)、hashCode()与equals()

  1. 如果两个对象相等,则hashcode一定也是相同的
  2. 两个对象相等,对两个equals方法返回true
  3. 两个对象有相同的hashcode值,它们也不一定是相等的
  4. 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖
  5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。

你可能感兴趣的:(Java基础)