Java源码分析——java.util工具包解析(二)——HashSet、TreeSet、LinkedHashSet类解析

版权声明:博主GitHub地址https://github.com/suyeq欢迎大家前来交流学习 https://blog.csdn.net/hackersuye/article/details/84331177

    Set,即集合,与数学上的定义一样,集合具有三个特点:

  1. 无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的。
  2. 互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。
  3. 确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现。

    但是Java中的集合并不是严格意义上的集合,其中的TreeSet集合类并不满足,因为它是有序的,除了无序性这一点,Java中的集合都严格满足其它两点。
    在Java中将集合类的起源定义为Set接口,并由该接口扩展出其他具体的实现,它们之间的关系如下:
在这里插入图片描述

    SortedSet接口继承自Set接口,在其内部定义了排序的行为交由TreeSet实现排序的集合。在AbstractSet抽象类中,与AbstractList类一样,为其子类提供对其自身的操作,即集合类操作,只是集合的内部操作,并没有实现集合间的操作。

HashSet

    HashSet类是满足集合属性的三个属性的,插入到其内部的元素是有其hashcode值决定的,其内部的具体实现是由HashMap完成的,平时我们创建一个新的HashSet类,实际上是创建了一个HashMap来完成我们所需的操作,HashSet类的几个构造方法如下:

	private transient HashMap<E,Object> map;
	
    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);
    }
    
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    可见里面都创建了HashMap对象,也就是说,HashSet是利用HashMap的不可重复性来完成集合的互斥性的,示例代码:

		String s1=new String("1");
        String s2=new String("1");
        String s3=new String("1");
        Set<String> set=new HashSet<>();
        set.add(s1);
        set.add(s2);
        set.add(s3);
        System.out.println(set.add(s1));//false
        Iterator iterable=set.iterator();
        while (iterable.hasNext()){
            System.out.println(iterable.next());//输出:1
        }
        System.out.println(s1.hashCode()==s2.hashCode());//true

    HashMap是根据对象的hashcode值来判断是否是同一个对象的,因为s1、s2、s3的值相同,所以它们的hashcode值也相同,在集合中加入s1与s2时加不进去。下面列出常用的方法:

	//获取迭代器
	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();
    }

TreeSet

    TreeSet类是有序的集合类,它实现了SortedSet接口,但与HashSet类相同的是,它也是在内部委托给另外一个类来完成其功能的,这个类是TreeMap类,TreeMap类在其内部实现了红黑树,因此可以实现较快的排序:

 public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    还可以直接返回第一个元素以及最后一个元素:

	public E first() {
        return m.firstKey();
    }
    public E last() {
        return m.lastKey();
    }

    加入到TreeMap中的元素必须实现Comparable与Comparator接口,用来进行比较,其示例代码如下:

		String s1=new String("1");
        String s2=new String("3");
        String s3=new String("2");
        Set<String> set=new TreeSet<>();
        set.add(s1);
        set.add(s2);
        set.add(s3);
        Iterator iterable=set.iterator();
        while (iterable.hasNext()) {
            System.out.println(iterable.next());
        }
  		//输出为:1 2 3

LinkedHashSet

    LinkedHashSet继承自HashSet,它不同于HashSet里面的元素是无序的,它是按照元素的插入顺序来保存元素的,也就是说它是线性的,其内部是调用类父类的构造方法:

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

    采用了LinkedHashMap来实现其功能,LinkedHashMap是线性的HashMap,所以LinkedHashSet即为线性的。示例代码:

String s1=new String("1");
        String s2=new String("32");
        String s3=new String("243242");
        Set<String> set=new HashSet<>();
        set.add(s1);
        set.add(s2);
        set.add(s3);
        Iterator iterable=set.iterator();
        while (iterable.hasNext()) {
            System.out.println(iterable.next());
        }
        //输出:1 243242 32
        Set<String> set2=new LinkedHashSet<>();
        set2.add(s1);
        set2.add(s2);
        set2.add(s3);
        Iterator iterable2=set2.iterator();
        while (iterable2.hasNext()) {
            System.out.println(iterable2.next());
        }
        //输出:1 32 243242

    总的来说,三者其实是Map类的一个封装而已。

猜你喜欢

转载自blog.csdn.net/hackersuye/article/details/84331177
今日推荐