Java集合框架:Set(HashSet,LinkedHashSet,TreeSet)

简介: Set概述 Set几乎都是内部用一个Map来实现, 因为Map里的KeySet就是一个Set,而value是假值,全部使用同一个Object。Set的特征也继承了那些内部Map实现的特征。

Set概述

 Set几乎都是内部用一个Map来实现, 因为Map里的KeySet就是一个Set,而value是假值,全部使用同一个Object。Set的特征也继承了那些内部Map实现的特征。


HashSet

1. 定义

package java.util;
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();
    public HashSet() {
        map = new HashMap<>();
    }
//其余省略
}

2. 概述

 HashSet是基于HashMap来实现的,操作很简单,更像是对HashMap做了一次“封装”,而且只使用了HashMap的key来实现各种特性,而HashMap的value始终都是PRESENT。
HashSet不允许重复(HashMap的key不允许重复,如果出现重复就覆盖),允许null值,非线程安全
 罗列几个主要方法:

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

3. 使用

 案例1:

        Set<String> set = new HashSet<>();
        set.add("s2");
        set.add("s3");
        set.add("s4");
        set.add("s2");
        set.add("s5");
        set.add("s1");
        set.add(null);
        set.add("s21");
        set.add("sw2");
        set.add("s2");
        for(String i:set)
            System.out.println(i);
        System.out.println(set);

 输出:

null
s2
s1
sw2
s21
s5
s3
s4
[null, s2, s1, sw2, s21, s5, s3, s4]

LinkedHashSet

1. 定义(整个LinkedHashSet的代码)

package java.util;
public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = -2851667679971038690L;

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

2. 概述

 HashSet有4个共有的构造函数:

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

 还有一个包级私有的构造函数:

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

 这个构造函数就是LinkedHashSet的关键,整个LinkedHashSet的四个构造函数全部都是调用了HashSet中的这个包级私有的构造函数(构造函数中的dummy就是标记,无实用,为了实现方法的重载而已),也就是说LinkedHashSet就是基于LinkedHashMap实现的

3. 使用

案例2:

        Set<String> set = new LinkedHashSet<>();
        set.add("s2");
        set.add("s3");
        set.add("s4");
        set.add("s2");
        set.add("s5");
        set.add("s1");
        set.add(null);
        set.add("s21");
        set.add("sw2");
        set.add("s2");
        for(String i:set)
            System.out.println(i);
        System.out.println(set);

 输出:

s2
s3
s4
s5
s1
null
s21
sw2
[s2, s3, s4, s5, s1, null, s21, sw2]

允许null值,保留插入顺序,非线程安全。


TreeSet

1. 定义

package java.util;
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();
    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);
    }
//其余省略
}

2. 概述

 TreeSet的内部基于TreeMap实现,同样value永远为PRESENT.
 案例3:

        Set<String> set = new TreeSet<String>();
        set.add("s2");
        set.add("s3");
        set.add("s4");
        set.add("s2");
        set.add("s5");
        set.add("s1");
//        set.add(null);
        set.add("s21");
        set.add("sw2");
        set.add("s2");
        for(String i:set)
            System.out.println(i);
        System.out.println(set);

 运行结果:

s1
s2
s21
s3
s4
s5
sw2
[s1, s2, s21, s3, s4, s5, sw2]

不允许重复,不允许null值(如果有基于null的比较器,就可以允许为null),默认按升序排列。
案例4(其中的Person2详细见《Comparable与Comparator浅析》):

        Set<Person2> set = new TreeSet<Person2>(new Comparator<Person2>(){
            @Override
            public int compare(Person2 o1, Person2 o2)
            {
                if(o1==null || o2==null)
                    return 0;
                return o1.getAge()-o2.getAge();
            }
        });
        Person2 p1 = new Person2("zzh",18);
        Person2 p2 = new Person2("jj",17);
        Person2 p3 = new Person2("qq",19);
        Person2 p4 = new Person2(null,19);
        set.add(p1);
        set.add(p2);
        set.add(p3);
        set.add(p4);

        System.out.println(set);

 输出结果:[jj:17, zzh:18, qq:19]
 可以看到不是强制性要求TreeSet的键为null。


参考资料:
1. 《Comparable与Comparator浅析

目录
相关文章
|
3天前
|
存储 Java C++
Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列
Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列
17 0
|
15天前
|
存储 Java 编译器
Java集合丛林:深入了解集合框架的秘密
Java集合丛林:深入了解集合框架的秘密
16 0
Java集合丛林:深入了解集合框架的秘密
|
18天前
|
Java BI
Java 获取周,月,年日期集合(统计图)
Java 获取周,月,年日期集合(统计图)
Java 获取周,月,年日期集合(统计图)
|
29天前
|
存储 安全 Java
【Java技术专题】「Guava开发指南」手把手教你如何进行使用Guava工具箱进行开发系统实战指南(不可变集合篇)
【Java技术专题】「Guava开发指南」手把手教你如何进行使用Guava工具箱进行开发系统实战指南(不可变集合篇)
30 1
|
3天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
17 3
|
1月前
|
存储 自然语言处理 C++
map和set的简单介绍
map和set的简单介绍
20 1
|
1月前
|
存储 安全 Java
java集合框架及其特点(List、Set、Queue、Map)
java集合框架及其特点(List、Set、Queue、Map)
|
3月前
|
JavaScript 前端开发 定位技术
JavaScript 中如何代理 Set(集合) 和 Map(映射)
JavaScript 中如何代理 Set(集合) 和 Map(映射)
50 0
|
3月前
|
存储 安全 Java
Map和Set(JAVA)
Map和Set(JAVA)
50 1
|
3月前
|
编译器 C++ 容器
【C++学习手札】基于红黑树封装模拟实现map和set
【C++学习手札】基于红黑树封装模拟实现map和set