一.Set

1.泛型

  1. jdk1.5引入,之前都是使用Object[]
  2. 使用Object[]的缺点
    • 获取一个值时,必须进行强制类型转换
    • 调用一个方法前,必须使用instanceof判断对象类型

2.泛型的好处

  1. 减少了强制类型转换的次数
  2. 获取数据值更加方便
  3. 调用方法时更加安全
  4. 泛型只在编译时期起作用,运行阶段JVM看不见泛型类型(因为进行了类型擦除所以JVM只能看见对应的原始类型)
  5. 在使用时没有指定泛型类型时,默认使用Object类
  6. 支持lambda表达式

二.HashSet

1.特点

HashSet是无序的(无下标),并且数据不可重复,他的底层维护的是HashMap中key的部分,允许存入null元素。

2.属性

    //序列化ID
    static final long serialVersionUID = -5024744406713321676L;
    //底层使用HashMap来保存数据
    private transient HashMap<E,Object> map;
    //由于Set只使用到了HashMap的key,所以此处定义一个静态的常量Object类,来充当HashMap的value
    private static final Object PRESENT = new Object();

3.内部方法

(1).构造方法
//使用HashMap的默认容量大小16和默认扩容因子0.75初始化map,构造一个HashSet
public HashSet() {
        map = new HashMap<>();
    }
//构造一个指定Collection参数的HashSet,这里不仅仅是Set,只要实现Collection接口的容器都可以
public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        //使用Collection实现的Iterator迭代器,将集合c的元素一个个加入HashSet中
        addAll(c);
    }
public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }
//使用指定的初始容量大小和扩容因子初始化map,构造一个HashSet
public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
//使用指定的初始容量大小和默认的扩容因子0.75初始化map,构造一个HashSet
public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
//不对外公开的一个构造方法(默认default修饰),底层构造的是LinkedHashMap,dummy只是一个标示参数,无具体意义
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
(2).add方法
//使用HashMap的add方法,将传入的值存为map的key,value使用一个静态值填充
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
(3).remove方法
//调用HashMap的remove方法实现删除
 public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }
(4)contains方法
//调用HashMap的containsKey方法判断元素是否存在
public boolean contains(Object o) {
        return map.containsKey(o);
    }

三.TreeSet

1.特点

TreeSet是无序的(无下标),并且数据不可重复,但是可以排序,他的底层一般都是维护了一个TreeMap(基于构造方法)。

2.属性

    /*
    TreeMap实现了NavigableMap接口
    存储的是一个NavigableMap。
    TreeMap实现了NavigableMap。
    所以TreeSet内部不一定就是使用的TreeMap。
    */
    private transient NavigableMap<E,Object> m;
    //静态常量Object类
    private static final Object PRESENT = new Object();

3.内部方法

(1).构造方法
//通过NavigableMap直接赋值给TreeSet内部的m,此时内部使用的就是NavigableMap。
TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }
//新建一个TreeMap作为底层存储空间,key为泛型,因为不使用到value所以定义为一个Object类用PRESENT来填充
public TreeSet() {
        this(new TreeMap<E,Object>());
    }
//通过传入一个比较器构建TreeSet(用于排序)
public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }
//构造一个指定Collection参数的TreeSet,通过addAll将所有值传入
public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }
//通过传入的排序集合创建一个相同排序的集合
public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }
(2).add方法
//只使用Key来存储数据
public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
(3).addAll方法
/*
如果TreeSet是空的,调用了addAll方法后,会直接创建一个TreeMap
*/
public  boolean addAll(Collection<? extends E> c) {
        // Use linear-time version if applicable
        if (m.size()==0 && c.size() > 0 &&
            c instanceof SortedSet &&
            m instanceof TreeMap) {
            SortedSet<? extends E> set = (SortedSet<? extends E>) c;
            TreeMap<E,Object> map = (TreeMap<E, Object>) m;
            Comparator<?> cc = set.comparator();
            Comparator<? super E> mc = map.comparator();
            if (cc==mc || (cc != null && cc.equals(mc))) {
                map.addAllForTreeSet(set, PRESENT);
                return true;
            }
        }
        return super.addAll(c);
    }
(4).remove方法
//调用底层map的remove方法进行删除
public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }

四.LinkedHashSet

1.特点

LinkedHashSet是Set集合的一个实现,继承了HashSet,具有Set集合不重复的特点,因为采用了双向链表,所以其顺序就是插入顺序。

2.构造方法

//都是调用父类(HashSet)来构造的,HashSet的底层实际上是HashMap,所以传入一个容量为16,扩容因子为0.75
public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

public LinkedHashSet() {
        super(16, .75f, true);
    }

public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

每个不起眼的日子,都是反败为胜的资本