JDK9.0 HashSet源码阅读记录

时间:2023-02-07 17:01:25

Set接口

Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。

以下是HashMap中添加元素时的检测,判断对象是否是同一个
判断hash是否相等,并且 == 或者 equals为true.
如果添加的对象没用重写equals,其仍然是采用==进行判断.
 

if (e.hash == hash &&
   ((k = e.key) == key || (key != null && key.equals(k))))
 public boolean equals(Object obj) {
   return (this == obj);
}

HashMap的key是不允许重复的,HashSet就是依赖这个特性实现其元素值不重复的功能,HashSet是基于HashMap来实现的,其对数据的操作调用的是HashMap的相关方法.具体HashMap的实现原理可以查看Java9.0 HashMap源码阅读记录

继承体系

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable

私有属性

HashSet只有两个私有属性,一个是HashMap类型,因为HashSet是基于HashMap来实现的.
一个是final Object类型,在执行添加操作时,value都是这个对象,而key是用户要添加的数据.

 private transient HashMap<E,Object> map;
 private static final Object PRESENT = new Object();

构造器

使用默认参数构造一个HashMap对象

public HashSet() {
    map = new HashMap<>();
}

指定初始容量,这里这么写的原因我觉得是避免在添加集合元素时出现扩容,而HashMap默认的加载因子是0.75,(c.size()/.75f) + 1确保了添加最后一个元素时不会进行扩容.

 public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}

指定初始容量和加载因子

public HashSet(int initialCapacity, float loadFactor) {
   map = new HashMap<>(initialCapacity, loadFactor);
}

指定加载因子

public HashSet(int initialCapacity) {
   map = new HashMap<>(initialCapacity);
}

指定初始容量和加载因子,可以忽略.
这里创建的是LinkedHashMap.这个

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
  map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

添加元素

可以看到其调用的是HashMap的put(方法,key为用户要添加的数据,value都是同一个对象.

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

移除元素

public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
}

其他方法

获取元素数量

public int size() {
 return map.size();
}

检测是否为空

public boolean isEmpty() {
    return map.isEmpty();
}

检测是否包含对象

public boolean contains(Object o) {
    return map.containsKey(o);
}

清空所有元素

 public void clear() {
  map.clear();
 }

迭代器

因为我们是将数据以key方式进行添加,因此迭代器获得的也是key的迭代器.

public Iterator<E> iterator() {
   return map.keySet().iterator();
}

实例

创建一个类

class Student{

    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

测试

HashSet<Student>  hashSet = new HashSet<Student>();

//对象1
Student  student1 = new Student("LiNing");
hashSet.add(student1);
   //对象2
Student  student2 = new Student("zhanggang");
hashSet.add(student2);

System.out.println("foreach 访问方式");
for(Student stu:hashSet) {
    System.out.println(stu.getName());
}
System.out.println("迭代器 访问方式");
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
    System.out.println(((Student)iterator.next()).getName());

}

输出

foreach 访问方式
LiNing
zhanggang
迭代器 访问方式
LiNing
zhanggang

相关文章

JDK9.0 ArrayList源码阅读记录
JDK9.0 LinkedList源码阅读记录
ArrayList和LinkedList性能比较
JDK9.0 Vector源码阅读记录
JDK9.0 Hashtable源码阅读记录
Java9.0 HashMap源码阅读记录
JDK9.0 HashSet源码阅读记录