java基础学习之集合-SET

java里集合的set是一种无序,不能重复的集合,Set直接继承了Collection,是一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象

HashSet的介绍

HashSet 是一个没有重复元素的集合。
它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素。
HashSet是非同步的。可以通过
Set s = Collections.synchronizedSet(new HashSet(...));
来实现同步。
此类的 iterator 方法返回的迭代器是快速失败 的:在创建迭代器之后,如果对 set 进行修改,除非通过迭代器自身的 remove 方法,否则在任何时间以任何方式对其进行修改,Iterator 都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来在某个不确定时间发生任意不确定行为的风险。
HashSet的构造器:

// 默认构造函数
public HashSet() {
 //调用hashMap的构造函数,生成一个map
 map = new HashMap<>();
}

// 带集合的构造函数
public HashSet(Collection<? extends E> c) {
    //调用hashMap的构造器,利用Math的max方法得到c.size()/.75f) + 1 与 16的较大值,在hashMap里,从效率(时间成本和空间成本)来考虑,HashMap的加载因子是0.75,
    //并且当HashMap的“阈值”(阈值=HashMap总的大小*加载因子) < “HashMap实际大小”时,就需要将HashMap的容量翻倍
    //所以,(c.size()/.75f) + 1 计算出来的正好是总的空间大小。
    // HashMap的构造函数中也会重新计算,找出比“指定大小”大的最小的2的指数倍的数。
    // 所以,这里指定为16是从性能考虑。避免重复计算。
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    // 将集合中的全部元素都添加到HashSet中
        addAll(c);
}

// 指定HashSet初始容量和加载因子的构造函数
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}

// 指定HashSet初始容量的构造函数
public HashSet(int initialCapacity) 

// 指定HashSet初始容量和加载因子的构造函数,dummy没有任何作用
HashSet(int initialCapacity, float loadFactor, boolean dummy){
map = new HashMap<>(initialCapacity);
}

当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

HashSet的数据结构

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable { }

通过源码可以看到直接继承了AbstractSet,并且实现了Set接口。HashSet的本质是一个”没有重复元素”的集合,它是通过HashMap实现的。HashSet中含有一个”HashMap类型的成员变量”map,HashSet的操作函数,实际上都是通过map实现的。

private transient HashMap<E,Object> map;
//PRESENT是向map中插入key-value对应的value,hashSet只需要map的键,所以对每个键都插入一个值,值固定都是PRESENT
private static final Object PRESENT = new Object();

这里可以更加了解hashSet是hashMap实现的,它的方法也都是靠hashMap来实现的。
遍历Set方法:

for(String s:set){
    System.out.println(s);
}
//使用iterator迭代器
for(Iterator iter = set.iterator();iter.hasNext();){
    String s = (String)iter.next();
    System.out.println(s);
}

TreeSet的介绍

TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable

TreeSet继承了AbstractSet,实现来NavigableSet,Cloneable,Serializable接口,AbstractSet提供 Set 接口的基本实现,NavigableSet是继承了 SortedSet的,具有了为给定搜索目标报告最接近匹配项的导航方法。方法 lower、floor、ceiling 和 higher 分别返回小于、小于等于、大于等于、大于给定元素的元素,如果不存在这样的元素,则返回 null。Cloneable支持克隆,Serializable支持序列化。

 //底层使用NavigableMap来保存TreeSet的元素
 private transient NavigableMap<E,Object> m;
 ///PRESENT会被当做Map的value与key构建成键值对
 private static final Object PRESENT = new Object();

构造方法:

   //使用指定的navigable map来构造TreeSet
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

    //默认构造方法,底层使用TreeMap来存储TreeSet元素
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
    // 使用指定的构造器,构造一个TreeMap来保存TreeSet的数据
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<E,Object>(comparator));
    }
    // 构造一个指定Collection参数的TreeSet
    public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    } 
   // 构造一个指定SortedMap的TreeSet,根据SortedMap的比较器来来维持TreeSet的顺序
    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
       addAll(s);
    }

看到了它的实现是靠NavigableMap,那么NavigableMap是什么呢?点进去发现这是个接口,有很多方法

public interface NavigableMap<K,V> extends SortedMap<K,V> {
    // 获取小于指定key的第一个节点对象
    Map.Entry<K,V> lowerEntry(K key);

    // 获取小于指定key的第一个key
    K lowerKey(K key);

    // 获取小于或等于指定key的第一个节点对象
    Map.Entry<K,V> floorEntry(K key);

    // 获取小于或等于指定key的第一个key
    K floorKey(K key);

    // 获取大于或等于指定key的第一个节点对象
    Map.Entry<K,V> ceilingEntry(K key);

    // 获取大于或等于指定key的第一个key
    K ceilingKey(K key);

    // 获取大于指定key的第一个节点对象
    Map.Entry<K,V> higherEntry(K key);

    // 获取大于指定key的第一个key
    K higherKey(K key);

    // 获取Map的第一个(最小的)节点对象
    Map.Entry<K,V> firstEntry();

    // 获取Map的最后一个(最大的)节点对象
    Map.Entry<K,V> lastEntry();

    // 获取Map的第一个节点对象,并从Map中移除改节点
    Map.Entry<K,V> pollFirstEntry();

    // 获取Map的最后一个节点对象,并从Map中移除改节点
    Map.Entry<K,V> pollLastEntry();

    // 返回当前Map的逆序Map集合
    NavigableMap<K,V> descendingMap();

    // 返回当前Map中包含的所有key的Set集合
    NavigableSet<K> navigableKeySet();

    // 返回当前map的逆序Set集合,Set由key组成
    NavigableSet<K> descendingKeySet();

    // 返回当前map中介于fromKey(fromInclusive是否包含)和toKey(toInclusive是否包含) 之间的子map
    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                             K toKey,   boolean toInclusive);

    // 返回介于map第一个元素到toKey(inInclusive是否包含)之间的子map
    NavigableMap<K,V> headMap(K toKey, boolean inclusive);

    // 返回当前map中介于fromKey(inInclusive是否包含) 到map最后一个元素之间的子map
    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);

    // 返回当前map中介于fromKey(包含)和toKey(不包含)之间的子map
    SortedMap<K,V> subMap(K fromKey, K toKey);

    // 返回介于map第一个元素到toKey(不包含)之间的子map
    SortedMap<K,V> headMap(K toKey);

    // 返回当前map中介于fromKey(包含) 到map最后一个元素之间的子map
    SortedMap<K,V> tailMap(K fromKey);
}

NavigableMap继承了SortedMap接口,而SortedMap继承了Map接口,所以NavigableMap是在Map接口的基础上丰富了这些对于边界查询的方法,但是不妨碍你只是用其中Map中自身的功能。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值