文章四:Set接口与其子实现(HashSet、LinkedHashSet、TreeSet)(0312)


PM Lesson2
1 hour

在这里插入图片描述

在这里插入图片描述

(01) Set 是继承于Collection的接口。它是一个不允许有重复元素的集合。
(02) AbstractSet 是一个抽象类,它继承于AbstractCollectionAbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利。
(03) HastSet 和 TreeSet 是Set的两个实现类

    HashSet依赖于HashMap,它实际上是通过HashMap实现的。HashSet中的元素是无序的。
    TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。TreeSet中的元素是有序的。

(04) LinkedHashSet继承于HashSet,是具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。

我是红色分割


1 Set接口

概述

  1. Set接口是Collection接口的一个’’集合’’子接口
  2. Set一些子实现是有序的: LinkedHashSet, TreeSet(大小有序);一些子实现是无序的: HashSet
  3. 不允许存储””重复””元素 (set存储的内容, 实际上都是要存到底层持有的map对象上, 并且作为key存在)
  4. 有些实现允许存储null: hashset linkedhashset;有些子实现不允许存储null: treeset

Api

在这里插入图片描述

2 HashSet

概述

  1. 他是Set接口的一个子实现
  2. 底层持有一个hashmap对象(添加到hashset中的元素, 实际上都作为key添加到底层hashmap中了)
  3. 底层结构, hashmap对象, 数组+链表+红黑树
  4. 无序
  5. 允许存储null
  6. 不允许重复( hash值一样 并且(存储元素直接相等 或者 相equals ))
  7. 线程不安全

构造方法

在这里插入图片描述

Api

在这里插入图片描述

源码分析(个人)

核心成员变量
HashSet底层是基于HashMap存储数据,该map的key就是HashSet要存放的数据
private transient HashMap<E,Object> map;

该变量用来填充上一个map的value字段,因为HashSet关注的是map的Key
哑变量, 没有什么实际含义, 也没有什么特殊的作用, 仅用来填充key-value结构的value值
private static final Object PRESENT = new Object();
无参构造函数
public HashSet() {
    
    
    //实例化map成员变量
    map = new HashMap<>();
}

hashSet底层是基于hashMap实现的,hashSet存放的数据实际就是hashMap的key,而hashMap的value存放的是一个静态的final对象PERSENT
当调用hashSet无参构造函数的时候,实际只是实例化了hashMap对象

源码结构(个人Typora整理)(重要收获,看这个就够了!)
//HashSet类:
//底层持有一个hashmap对象(添加到hashset中的元素, 实际上都作为key添加到底层hashmap中了)

下面的特点基于hashmap???
//无序
//允许存储null
//不允许重复

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    
    	
    
    核心成员变量、无参构造函数
    private transient HashMap<E,Object> map;
    
    private static final Object PRESENT = new Object();
    
    构造方法5public HashSet() {
    
    
        map = new HashMap<>();
    }
    
    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);
    }
    
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    
    
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    
    实现抽象类AbstractCollection中的抽象方法
    public Iterator<E> iterator() {
    
    
        return map.keySet().iterator();
    }
    public int size() {
    
    return map.size();}
    public boolean isEmpty() {
    
    return map.isEmpty();}
    public boolean contains(Object o) {
    
    return map.containsKey(o);}
    public boolean add(E e) {
    
    return map.put(e, PRESENT)==null;}
    public boolean remove(Object o) {
    
    return map.remove(o)==PRESENT;}
    public void clear() {
    
    map.clear();}
    
    Object中的
    public Object clone() {
    
    
        try {
    
    
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
    
    
            throw new InternalError(e);
        }
    }
    自己定义的私有方法
    
}

源码(个人)

AbstractSet抽象类

此类提供 Set 接口的骨干实现,从而最大限度地减少了实现此接口所需的工作。

注意,此类并没有重写 AbstractCollection 类中的任何实现(包括add()方法)。

它仅仅添加了 equals 和 hashCode 的实现。
源码
public class HashSet<E>				继承AbstractSet抽象类,实现Set接口
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable


HashSet继承的AbstractSet抽象类 extends AbstractSet<E>
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
    
    

HashSet实现的Set接口 implements Set<E>
public interface Set<E> extends Collection<E> {
    
    

抽象类AbstractSet继承的AbstractCollection抽象类
public abstract class AbstractCollection<E> implements Collection<E> {
    
    

抽象类AbstractSet实现的Set接口
public interface Set<E> extends Collection<E>{
    
    

AbstractCollection 抽象类

此类提供 Collection 接口的骨干实现,以最大限度地减少了实现此接口所需的工作。
继承此抽象类的直接已知子类有:AbstractList,AbstractQueue,AbstractSet,ArrayDeque。

要实现一个不可修改的collection,编程人员只需扩展此类,并提供iterator()size()方法的实现,
其中iterator()方法返回的迭代器必须实现 hasNext()next()。

要实现可修改的collection,编程人员必须另外重写此类的add()方法,否则,会抛出 UnsupportedOperationException),
iterator()方法返回的迭代器还必须另外实现其 remove()方法。

AbstractCollection 抽象类的所有源代码

package day312.analyse;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;

/**
 * @AUTHOR ZHANG
 * @data 2021/3/12 22:36
 */


public abstract class AbstractCollection<E> implements Collection<E> {
    
    

    protected AbstractCollection() {
    
    
    }

    public abstract Iterator<E> iterator();

    public abstract int size();

    public boolean isEmpty() {
    
    
        return size() == 0;
    }

    public boolean contains(Object o) {
    
    
        Iterator<E> it = iterator();
        //集合中可以含有null值
        if (o==null) {
    
    
            while (it.hasNext())
                if (it.next()==null)
                    return true;
        } else {
    
    
            while (it.hasNext())
                if (o.equals(it.next()))
                    return true;
        }
        return false;
    }

    //返回包含此 collection中所有元素的数组。
    public Object[] toArray() {
    
    
        // Estimate size of array; be prepared to see more or fewer elements
        Object[] r = new Object[size()];
        Iterator<E> it = iterator();
        for (int i = 0; i < r.length; i++) {
    
    
            if (! it.hasNext()) // fewer elements than expected
                return Arrays.copyOf(r, i); //返回一个长度为i的数组,元素为r中相应的值
            r[i] = it.next();
        }
        //finishToArray(r, it) ensures more elements than expected
        //r数组已经填满了所有的元素,但如果迭代器中仍有元素,则通过finishToArray(r, it)来重新调整
        return it.hasNext() ? finishToArray(r, it) : r;
    }

    //返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
    
    
        // Estimate size of array; be prepared to see more or fewer elements
        int size = size();
        T[] r = a.length >= size ? a :
                (T[])java.lang.reflect.Array
                        .newInstance(a.getClass().getComponentType(), size);
        Iterator<E> it = iterator();

        for (int i = 0; i < r.length; i++) {
    
    
            if (! it.hasNext()) {
    
     // fewer elements than expected
                if (a == r) {
    
    
                    r[i] = null; // null-terminate
                } else if (a.length < i) {
    
    
                    return Arrays.copyOf(r, i);
                } else {
    
    
                    System.arraycopy(r, 0, a, 0, i);
                    if (a.length > i) {
    
    
                        a[i] = null;
                    }
                }
                return a;
            }
            r[i] = (T)it.next();
        }
        // more elements than expected
        return it.hasNext() ? finishToArray(r, it) : r;
    }

    //可分配给数组的最大长度
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 在toArray()方法中,如果迭代器中比预料中有更多的元素时,用已经存满的数组和迭代器完成toArray的填充工作
     *
     * @param r 已经存满元素的数组
     * @param it collection的正在处理的迭代器
     * @return 返回包含给定数组r中的所有元素和迭代器it返回的所有元素的数组
     */
    @SuppressWarnings("unchecked")
    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    
    
        int i = r.length;
        while (it.hasNext()) {
    
      //迭代器
            int cap = r.length;
            if (i == cap) {
    
    
                int newCap = cap + (cap >> 1) + 1; //新数组扩容1.5倍
                // overflow-conscious code
                if (newCap - MAX_ARRAY_SIZE > 0)
                    newCap = hugeCapacity(cap + 1);
                r = Arrays.copyOf(r, newCap); //返回一个长度为newCap,元素包含r中所有元素的数组
            }
            r[i++] = (T)it.next(); //将迭代器中返回的元素逐个放入数组中
        }
        // trim if overallocated
        return (i == r.length) ? r : Arrays.copyOf(r, i);
    }

    private static int hugeCapacity(int minCapacity) {
    
    
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError
                    ("Required array size too large");
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    // Modification Operations
    public boolean add(E e) {
    
    
        throw new UnsupportedOperationException();
    }

    //从此 collection中移除指定的元素
    //注意如果iterator()方法返回的迭代器没有实现remove()方法,则在删除指定元素时会报UnsupportedOperationException
    public boolean remove(Object o) {
    
    
        Iterator<E> it = iterator(); //
        if (o==null) {
    
    
            while (it.hasNext()) {
    
    
                if (it.next()==null) {
    
    
                    it.remove();  //利用迭代器实现的remove()方法进行元素删除
                    return true;
                }
            }
        } else {
    
    
            while (it.hasNext()) {
    
    
                if (o.equals(it.next())) {
    
    
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }

    //如果此 collection 包含指定 collection 中的所有元素,则返回 true
    public boolean containsAll(Collection<?> c) {
    
    
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }

    //将指定 collection 中的所有元素都添加到此 collection中
    public boolean addAll(Collection<? extends E> c) {
    
    
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

    //移除此 collection 中那些也包含在指定 collection中的所有元素
    public boolean removeAll(Collection<?> c) {
    
    
        Objects.requireNonNull(c); //检查给定的对象引用是否为null,若是,抛出NullPointerException
        boolean modified = false;
        Iterator<?> it = iterator();
        while (it.hasNext()) {
    
    
            if (c.contains(it.next())) {
    
     //如果给定的集合中包含该元素,则删除
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

    //仅保留此 collection 中那些也包含在指定 collection的元素,和removeAll(Collection<?> c)正好相反
    public boolean retainAll(Collection<?> c) {
    
    
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<E> it = iterator();
        while (it.hasNext()) {
    
    
            if (!c.contains(it.next())) {
    
     //如果给定的集合中不包含该元素,则删除
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

    //移除此 collection中的所有元素
    public void clear() {
    
    
        Iterator<E> it = iterator();
        while (it.hasNext()) {
    
    
            it.next();
            it.remove();
        }
    }

    //返回此 collection 的字符串表示形式:[e1, e2, ...]
    public String toString() {
    
    
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
    
    
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }
}

源代码结构

1
//
protected AbstractCollection() {
    
    }
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2
//overrides methods in Collection
public abstract Iterator<E> iterator();
public abstract int size();

3
//implement methods in Collection	实现Collection接口中的方法
isEmpty()
contains(Object o)
toArray()
toArray(T[] a)
add(E e)
remove(Object o)
containsAll(Collection<?> c)
addAll(Collection<? extends E> c)
removeAll(Collection<?> c)
retainAll(Collection<?> c)
clear()


4
//self
finishToArray(T[] r, Iterator<?> it)
hugeCapacity(int minCapacity)

5
//overrides method in Object
toString()

3 LinkedHashSet

概述

  1. 他是HashSet子类
  2. 底层持有的是一个LinkedHashMap对象
  3. 有序: (因为LinkedHashMap底层维护了一个双向链表)
  4. 允许null
  5. 不允许重复
  6. 线程不安全

构造方法

在这里插入图片描述

4 TreeSet

概述

1, TreeSet是Set接口一个”树”实现
2, TreeSet底层持有一个TreeMap对象
3, TreeSet存储元素, 需要比较大小

比较方式1, 让存储的元素实现自然顺序
比较方式2, 给TreeSet提供一个比较器 
java中接口之间的关系 Collection<----继承---Set<----继承----SortedSet<----实现---TreeSet

TreeSet 实现SortedSet接口,此接口用于排序操作,因此该接口的实现类具有排序能力,下面主要通过小工具进行说明

一.首先看一下对基本类型的排序

结论:默认进行正序排列

二.如果里面存储自定义类型,当存入自定义的引用类型的时候就必须考虑到元素不可重复的这个特性,不然会报Exception in thread 
"main" java.lang.ClassCastException: testIoc.Teacher cannot be cast to java.lang.Comparable这种错误,
所以要对自定义类型进行处理,必须实现 Comparable与Compared接口,排序方式有自然排序和比较器排序。

(1) 自然排序

(2) 比较器排序

在这里插入图片描述

在这里插入图片描述

4, 大小有序
5, 不能存储重复元素
6, 不能存储null (null没有办法比较大小)
7, 线程不安全

构造方法

在这里插入图片描述

Api

在这里插入图片描述

源码分析(个人)

//TreeSet类
//Set接口一个”树”实现、底层持有一个TreeMap对象、存储元素需要比较大小、大小有序

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{
    
    
    核心成员变量
    private transient NavigableMap<E,Object> m;
    private static final Object PRESENT = new Object();
    
    TreeSet(NavigableMap<E,Object> m) {
    
    
        this.m = m;
    }
    
    4个构造方法
    public TreeSet() {
    
    
        this(new TreeMap<E,Object>());
    }
    
    public TreeSet(Comparator<? super E> comparator) {
    
    
        this(new TreeMap<>(comparator));
    }
    
    public TreeSet(Collection<? extends E> c) {
    
    
        this();
        addAll(c);
    }
    
    public TreeSet(SortedSet<E> s) {
    
    
        this(s.comparator());
        addAll(s);
    }
    
    实现抽象类AbstractCollection中的抽象方法
    public Iterator<E> iterator() {
    
    
        return m.navigableKeySet().iterator();
    }
    
    public int size() {
    
    
        return m.size();
    }
    
    public boolean isEmpty() {
    
    
        return m.isEmpty();
    }
    
    public boolean contains(Object o) {
    
    
        return m.containsKey(o);
    }
    
    public boolean add(E e) {
    
    
        return m.put(e, PRESENT)==null;
    }
    
    public boolean remove(Object o) {
    
    
        return m.remove(o)==PRESENT;
    }
    
    public void clear() {
    
    
        m.clear();
    }
    
    public  boolean addAll(Collection<? extends E> c) {
    
    ...}
    
    实现接口NavigableSet中的抽象方法
    public Iterator<E> descendingIterator() {
    
    
        return m.descendingKeySet().iterator();
    }
    
    public NavigableSet<E> descendingSet() {
    
    
        return new TreeSet<>(m.descendingMap());
    }
    
    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                                  E toElement,   boolean toInclusive) {
    
    
        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
                                       toElement,   toInclusive));
    }
    
    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
    
    
        return new TreeSet<>(m.headMap(toElement, inclusive));
    }
    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
    
    
        return new TreeSet<>(m.tailMap(fromElement, inclusive));
    }
    
    public SortedSet<E> subSet(E fromElement, E toElement) {
    
    
        return subSet(fromElement, true, toElement, false);
    }
    public SortedSet<E> headSet(E toElement) {
    
    
        return headSet(toElement, false);
    }
    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
    
    ...}
    public E lower(E e) {
    
    ...}
    public E floor(E e) {
    
    ...}
    public E ceiling(E e) {
    
    ...}
    public E pollFirst() {
    
    ...}
    public E pollLast() {
    
    ...}
    
    
    实现接口SortedSet中的抽象方法
    public Comparator<? super E> comparator() {
    
    
        return m.comparator();
    }
    public E first() {
    
    
        return m.firstKey();
    }
    public E last() {
    
    ...}
    
    
    Object
    public Object clone() {
    
    ...}
    
    自己定义的几个
}

猜你喜欢

转载自blog.csdn.net/AC_872767407/article/details/114708622