HashSet,LinkedHashSet,TreeSet

/ 默认分类 / 0 条评论 / 1179浏览

HashSet,LinkedHashSet,TreeSet

一.前言

HashMap中数据的存储是基于HashMap的,下面我们从源码分析下

二.HashSet

先来看下类结构

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

可以看到,这里有一个map成员变量,这就是HashSet实际存储元素位置的地方,从HashMap用来存储就可以知道,HashSet存储的数据是无序的,因为HashMap存储属于hash表存储, 数据是按照hash函数随机插入的,所以HashSet肯定没有按照索引位置遍历或者获取元素,因为hash表存储的数据是分散的,不是连续的;

HashSet中的操作比较少,下面一个个介绍.

    public 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);
    }

很简单,就是初始化HashMap嘛

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

很明显,HashSet存储的数据就是将元素存储在HashMap的key中,并且每次插入数据统一将map的value值设为同一个对象值PRESENT,所以HashSet中存储的数据就是 HashMap中的key,可想而知,HashSet中的数据是去重过的,因为HashMap中插入数据时按照键来计算hash槽位置,如果重复添加,那么因为hash值相同,并且元素也一样, 所以就会直接替换.

因为HashSet使用的是hash表,所以数据存储是分散的,所以也没有索引位置,所以不能使用fori遍历,但是可以使用迭代器,当然foreach循环hashset其实本质 也是使用的迭代器。

HashSet中的操作比较少,并且基本都是基于HashMap,关于HashMap我的其他博客文章已经介绍了,这里就不赘述。

LinkedHashSet

不同就是内部用的是LinkedHashMap,所以这就不多说了,我前面的博客已经总结了

TreeSet

TreeSet,同样的,肯定内部使用就是就是TreeMap

TreeMap内部使用的是红黑树存储数据,TreeMap实现了还实现了SortedMap接口,自带自然排序,当然也可以自己写一个排序比较器,自定义排序方式方式,即使用这个构造方法 .

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
    
public interface NavigableMap<K,V> extends SortedMap<K,V> {
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

可以按照你存储的元素对象.来自己实现一个自定义逻辑的比较器.
建议在需要排序的情况下使用TreeMap

所以同样的,TreeSet也就是支持排序功能:

    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

public class TestModelCompartor implements Comparator {

    @Override
    public int compare(Object o1, Object o2) {
        return (int) ((TestModel) o1).getS1().charAt(0) - (int) ((TestModel) o2).getS1().charAt(0);
    }

}

ps:关于TreeMap的源码的分析,见我的其他博客文章