【Java】高级9:Set集合专题

Set集合接口


概述

public interface Set<E> extends Collection<E>{
	//... ...
}
  • Package:java.util
  • Statement:Interface Set
  • Param Type :E - 由此集合维护的元素的类型
  • All Superinterfaces:Collection , Iterable
  • All Known Subinterfaces:NavigableSet , SortedSet
  • All Known Implement Class:AbstractSet HashSet TreeSet EnumSet LinkedHashSetCopyOnWriteArraySetConcurrentSkipListSet ,JobStateReasons ConcurrentHashMap.KeySetView
  • Discription:不包含重复元素的集合

注意!


  • Set集合不包含重复元素
  • Set集合中的元素是无序的,即添加时元素时的顺序和遍历时的顺序没任何关系。

HashSet

源码👇

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable,Serializable
{
    static final long serialVersionUID = -5024744406713321676L;
	//存放元素
    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

	// ... ...
 }

常用方法

添加元素

# add


    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

HashSetadd方法实际上是将元素作为 Mapkey值存到Map映射中,Map的value保存了一个默认值。由于Mapkey值是不可重复的,所以HashSet实现不重复还是依靠Map映射表中,key不重复的hash算法。

map在put一个键值对的时候会先计算key的hashCode值来判断元素插入的位置,同时也会和其他元素的hashcode值作比较,要是有相近的,再用equals()对比内容是否相同,若相同,则认为这个key是重复的,不允许插入。

注意!


HashSet对于自己创建的类,需要重写hashCode(),和equals()方法,对基本类型的数据和字符串类型已经重写了hashCode方法,和equals()方法。🔗

# addAll


    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

addAll方法是调用了分类AbstractSetaddAll方法,实际的处理逻辑是遍历集合调用add方法挨个添加。

删除元素

# void clear()


源码👇

public void clear() {
        map.clear();
    }

# boolean remove(Object o)


源码👇

    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;//调用了map的删除方法
    }

# boolean removeAll(Collection<?> c)


	//source:AbstractSet.removeAll
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        boolean modified = false;

        if (size() > c.size()) {
            for (Iterator<?> i = c.iterator(); i.hasNext(); )
                modified |= remove(i.next());
        } else {
            for (Iterator<?> i = iterator(); i.hasNext(); ) {
                if (c.contains(i.next())) {
                    i.remove();
                    modified = true;
                }
            }
        }
        return modified;
    }

# boolean removeIf(Predicate<? super E> filter)


源码👇

	//source:Collection.removeIf
    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }

修改元素

注意!


  • hashSet未提供修改元素的方法,若需要修改元素,先remove再add。

HashSet总结

  • HashSet不是线程安全的。
  • HashSet不能保证插入元素的顺序。
  • HashSet允许存在null元素

TreeSet

认识TreeSet

继承关系👇

java.lang.Object
 ↳     java.util.AbstractCollection<E>
       ↳     java.util.AbstractSet<E>
             ↳     java.util.TreeSet<E>

构造方法

# TreeSet()
无参构造方法。


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

无参的构造方法指定了NavigableMap接口的实现类,实际又调用了有参的构造方法,初始化了NavigableMap<E,Object> m;

# TreeSet(NavigableMap<E,Object> m)
含参构造方法,可指定一个NavigableMap接口的实现类。用来初始化NavigableMap<E,Object> m;


    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

!
TreeSet支持个性化拓展,可以自己写个类实现NavigableMap接口,然后初始化的时候将这个类传进去。

常用方法

添加元素

# boolean add(E e)
将指定元素添加到该集合,如果该元素在集合中不存在。


    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

Demo👇

     TreeSet<String> strTree = new TreeSet<>();
      strTree.add("a");
      strTree.add("b");
      strTree.add("c");
      Iterator<String> iterator = strTree.iterator();
      while (iterator.hasNext()){
          String next = iterator.next();
          System.out.println(next);
     }
//print:遍历出的顺序和插入时的顺序一样
	a
	b
	c

# boolean addAll(Collection<? extends E> c)
将指定集合中的所有元素添加到此集合中。


源码👇

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

删除元素

# void clear()
从此集合中删除所有元素。


源码👇

   public void clear() {
        m.clear();
    }

# boolean remove(Object o)
如果存在,则从该集合中删除指定的元素。


  public boolean remove(Object o) {
        return m.remove(o)==PRESENT;//调用TreeMap的remove方法
    }

Demo👇

        TreeSet<String> strTree = new TreeSet<>();
        // ... ...
        strTree.remove("a");
        Iterator<String> iterator = strTree.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);// b c 
        }

查找元素

# boolean contains(Object o)
如果此集合包含指定的元素,则返回 true 。


    public boolean contains(Object o) {
        return m.containsKey(o);//调用TreeMap的getEntry方法
    }

Demo👇

        TreeSet<String> strTree = new TreeSet<>();
		// ... ...
        boolean a = strTree.contains("a");
        System.out.println(a);//true

TreeSet总结

public class TreeSet<E> extends AbstractSet<E> 
	implements NavigableSet<E>, Cloneable, java.io.Serializable
{
    //可导航map的接口,由treeMap实现
    //底层还是由TreeMap实现的
    private transient NavigableMap<E,Object> m;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
  • TreeSet 是一个有序的集合,它的作用是提供有序的Set集合,插入元素的顺序和遍历元素的顺序一致。
  • 它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, java.io.Serializable接口。
  • TreeSet 继承于AbstractSet,所以它是一个Set集合,具有Set的属性和方法。
  • TreeSet 实现了NavigableSet接口,意味着它支持一系列的导航方法。比如查找与指定目标最匹配项。
  • TreeSet实现了Cloneable接口,意味着它能被克隆。
  • TreeSet 实现了java.io.Serializable接口,意味着它支持序列化。
  • TreeSet是基于TreeMap实现的。可以看作是对做了进一步封装。
  • TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet时提供的 Comparator进行排序。这取决于使用的构造方法。
  • TreeSet为基本操作(addremovecontains)提供受保证的 log(n) 时间开销。
  • TreeSet是非同步的。 它的iterator 方法返回的迭代器是fail-fast的。
  • TreeSet中的元素不需要重写 hashCode()equals() 方法,因为 TreeSet 是通过比较器去重的,所有元素都必须实现 Comparable 接口,然后重写 compareTo() 方法。

附录

该博客会基于日常积累,不定时更新或添加内容。

【Java】知识架构图

【Java】基础1:注释|基本数据类型|变量|运算符

【Java】基础2:字符串

【Java】基础3:控制流程|循环

【Java】基础4:类|对象|修饰符

【Java】基础4:数组

【Java】OOD5:继承|重写|重载|多态

【Java】OOD6:抽象类|接口|枚举

【Java】高级7:集合概述

【Java】高级8:List集合接口专题

【Java】高级9:Set集合专题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值