• java集合之Set接口


      Set集合通常不能记住元素添加的顺序,其他的操作和它的父接口基本相同。只是行为上有细微的差别,Set集合不能包含相同的元素。如果尝试添加相同的元素,调用add()方法将返回false,且新元素不能被加入容器。

    下面是Set接口的三个实现类,将一一介绍:

    1. HashSet

    HashSet 类具备以下特征:

    1. 不能保证元素的排列顺序,可能和添加的顺序不相同,也有可能会发生变化。
    2. HashSet不是线程安全的,如果多个线程同时访问HashSet,假设有两个以上的线程修改了HashSet集合时,在程序中必须要做同步处理。
    3. 集合元素值可以是null。

    在源码中,HashSet的实现调用HashMap的

    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;
    
        // Dummy value to associate with an Object in the backing Map
        private static final Object PRESENT = new Object();
        
        public HashSet() {
            map = new HashMap<>();
        }
        ... //省略其他源码
    }

      也就是说,当想HashSet中存入一个对象时,将调用该对象的hashCode()方法来的到该对象的hashCode值,然后根据hashCode值来得到该对象在HashSet中的位置。如果两个对象的hashCode值不同,就算是同一个对象,HashSet也会将他们存放在不同的位置,也就是说,HashSet集合判断两个元素相等的标准是两个对象通过调用equals()方法返回true,并且两个对象的hashCode()方法返回值也相等。因此,当我们在把自定义的对象放入HashSet的时候,都需要重写这个对象发equals()方法和hashCode()方法,重写hashCode方法的规则如下:

    1. 在程序运行中,同一个对象多次调用hashCode()方法的返回是一致的。
    2. 当两个对象的equals()方法返回为true时,hashCode()方法的返回值也应该相等。
    3. equals()方法中用作比较标准的实例变量,都应该用于计算hashCode值。

    2. LinkedHashSet

      LinkedHashSet是HashSet的子类,它也是根据元素的hashCode值来计算元素的存储位置的,并且同时使用链表来维护元素的次序,这样使得元素看起来像是有序的(插入顺序),当我们遍历LinkedHashSet中的元素时,将按照元素的插入顺序来访问集合中的元素。
      LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet,但是迭代Set中的所有的元素时,会有较好的性能,因为它是以链表来维护元素的顺序的。

    3. TreeSet

    • TreeSet是SortedSet接口的实现类,如名所示,TreeSet中的元素时有序的(大小序,而不是插入序)。

    • 与HashSet集合采用hashCode算法来决定元素的存储位置不同,TreeSet采用的是红黑树的数据结构来存储集合元素。但是TreeSet集合中的元素时按照上面规则来排序的呢?目前主持两种排序方式:

      1. 自然排序:加入TreeSet中的对象都实现Comparable接口,重写compareTo(Object obj)方法。同时需要保证加入TreeSet的而元素时同一类对象。
      2. 定制排序:加入TreeSet中的对象都实现Comparator接口,重写compare(T o1,T o2)方法。

    4. EnumSet

    • EnumSet是一个专为枚举类型设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet枚举类型的时候显式或者隐式的指定。EnumSet集合的元素也是有序的,顺序是枚举定义的类型。
    • EnumSet的内部以向量的形式存储,这样占用的空间小,效率高。EnumSet中不允许加入null值。

    总结:

    各Set实现类的性能分析

    1. HashSet和TreeSet是Set接口的两个典型的实现,如何选择呢?HashSet的性能总是比TreeSet好(特别是频繁的添加,查询操作),因为TreeSet需要额外的红黑树算法来维护集合的次序,只有需要集合有序的时候才使用TreeSet,否则都使用HashSet。
    2. HashSet 和其子类LinkedHashSet,对于普通的插入,删除操作,LinkedHashSet比HashSet要慢一些,因为LinkedHashSet需要维护链表额外开销,但是当需要遍历整个容器时,LinkedHashSet会更快。
    3. EnumSet是这几个实现当中性能最好的,但是EnumSet集合中只能存放枚举类的枚举值。

      注:Set接口中的所有实现HashSet、TreeSet、EnumSet、LinkedHashSet都不是线程安全的,当有两个以上线程同时修改时,必须在程序中手动实现同步性(通常可以使用Collections工具类中的synchronizedSortedSet方法来包装Set集合,最好是在创建的时候设置)。

  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/ytuan996/p/10573606.html
Copyright © 2020-2023  润新知