zoukankan      html  css  js  c++  java
  • Set集合

    Set接口是Collection接口的子接口,Set集合是无序的(但子类中有很多都是有序的),不能有重复的元素,如果用add()加入一个已有的元素,会添加失败,返回false。

    Set接口的继承关系:

    Set接口的常用实现类:

    1、HashSet

    • 按Hash算法来存储元素,具有良好的存储、查找性能。
    • 元素无序,就是说排列顺序和添加顺序可能不同
    • 不是同步的,如果多个线程同时访问、修改一个HashSet,必须要使用同步代码来保证同步。就是说HashSet不是线程安全的。
    • 元素的值可以是null

    HashSet添加元素(存储)的机制:

    先调用该元素的hashCode()方法获取hashCode值,根据hashCode值确定存储位置。

    如果该位置上没有元素,则说明HashSet集合中没有与之相同的元素,直接在该位置存储该元素。

    如果该位置已有元素,则使用equals()比较这两个元素,返回false则在此位置存储该元素(但这样会在一个位置存储多个元素,导致HashSet性能降低),返回true则添加失败,不存储此元素。

    hash,被翻译为哈希、散列。hash算法的价值在于速度,它能快速查找被检索的对象。查询某个元素时,根据hashCode值直接定位元素的存储位置,实现快速查找。如果在HashSet中有多个元素的hashCode相同(在一个位置存储了多个元素),会导致查找性能下降。

    为了保证HashSet的性能(一个位置只存储一个元素),我们需要重写元素所属类的hashCode()。

    重写规则:如果两个对象通过equals()返回true,则它们的hashCode()也应该相同。

    因为Java自带的类大多数都重写了Object的hashCode()方法,所以Java自带的类(包括String)、以及继承自这些类的自定义类一般都不必重写hashCode()。不会存入相同的元素,一个位置只存一个元素。

    如果要在HashSet中存储自定义的类(未继承自Java自带的类),则需要在定义该类时重写该类继承自Object的hashCode(),而重写hashCode(),又必须重写equals()。

    如果不重写,是可以存入该类相同的对象的(这里的相同是指对象本身相同、对象本身的存储地址可以不同)。注意HashSet存储的实际上是对象的引用。

    示例:

    1  HashSet hashSet=new HashSet();
    2         //Java自带的类,下面2个相同的String只会存入第一个。使用New String("ok")也一样
    3         hashSet.add("ok");
    4         hashSet.add("ok");
    1  HashSet hashSet=new HashSet();
    2         //这个自定义的类未重写hashCode()、equals()。下面2个相同的对象都会被存入
    3         hashSet.add(new MyClass("ok"));
    4         hashSet.add(new MyClass("ok"));

    重写示例:

     1 class MyClass{
     2     private String id;  //id唯一标识创建的实例
     3     private String name;
     4 
     5     public MyClass(String id,String name) {
     6         this.id = id;
     7         this.name = name;
     8     }
     9 
    10     //toString可以不重写,不强制要求
    11     @Override
    12     public String toString() {
    13         return id + ":" + name;
    14     }
    15 
    16     //重写hashCode(),返回唯一标识此对象的成员变量的hashCode
    17     @Override
    18     public int hashCode() {
    19         return id.hashCode();
    20     }
    21 
    22     //重写equals(),Object的equals()是根据对象地址来判断,我们重写的效果是要根据对象本身来判断
    23     @Override
    24     public boolean equals(Object object){
    25         if (this==object)   //判断是否是同一个对象
    26             return true;
    27         if (!(object instanceof MyClass))  //判断是否是此类的对象
    28             return false;  //如果不是,返回false
    29         //如果是此类的对象
    30         MyClass obj=(MyClass)object;   //强制类型转换
    31         boolean b=this.id.equals(obj.id);  //通过唯一标识对象的id来比较。成员变量id不一定要是单独的,可以是居民类的身份证号码、学生类的学号等。
    32         return b;
    33     }
    34 
    35     //可以自由添加其它的成员变量、方法
    36 
    37 }
    1  HashSet hashSet=new HashSet();
    2         //重写后只存入第一个
    3         hashSet.add(new MyClass("1","ok"));
    4         hashSet.add(new MyClass("1","ok"));

    HashSet是最常用的Set。

    LinkedHashSet类是HashSet的子类,具有HashSet的一切特性(依然不能有重复的元素),但其内部使用一个链表维持元素的插入顺序,就是说存取、查找时仍是按hashCode进行的,但同时维护了一个链表来保持元素的添加顺序,遍历LinkedHashSet时,根据链表依次访问(和存入的顺序相同)。

    因为维护了一个链表,存储、查找的性能略低于HashSet,但遍历时性能高于HashSet(根据链表进行遍历)。

    2、TreeSet

    Set接口有一个子接口SortedSet(有序的Set),TreeSet是SortedSet的一个实现类。

    TresSet类采用红黑树的数据结构来存储元素,元素是有序的,但并不是按存入顺序排序的,而是按炎元素的实际值排序的。

    TreeSet有2种排序方式:

    • 自然排序  这是TreeSet默认的排序方式。数值型按数值大小排列,字符按码值排列,Date、Time按时间戳的大小排列........默认升序。
    • 定制排序  按我们自定义的规则排序

    TreeSet具有父类的一切方法,还具有自身的一些方法:

    Object  first()   返回集合中的第一个元素

    Object last()    最后一个

    Object  lower(Object obj)   返回obj的前一个元素,默认自然排序(默认升序),所以是lower,略小于

    Object  higher(Object obj)  后一个

    SortedSet  subSet(Object start,Object end)   返回子集合

    SortedSet  headSet(Object end)   返回子集合

    SortedSet  tailSet(Object start)

    java中,一个区间,[a,b),都是包含前者,不包含后者。

    3、EnumSet

    EnumSet是专门为枚举类设计的集合类,EnumSet的所有元素都必须是某个枚举类的某个枚举值。必须要是同一个枚举类的。

    EnumSet是有序的,根据该枚举值在枚举类中的定义顺序来决定在EnumSet中的顺序。

    性能比较:

    TreeSet性能最好,因为不需要维持什么,没有其他开销。但应用不广泛,只能用于枚举类的枚举值。

    HashSet次之,尤其是存储(添加)、查找性能很高。

    TreeSet性能最差,因为要使用红黑树算法来维护集合的元素顺序。

    HashSet有一个子类:LinkedHashSet。

    存储(添加)、查找操作,HashSet性能要高于LinkedHashSet,因为LinkedHashSet内部要维护一个链表,有额外的开销。

    但正是由于链表,遍历集合时,LinkedHashSet要快于HashSet。

    Set的三个实现类:HashSet、TreeSet、EnumSet都不是线程安全的。

    当一个以上的线程访问、修改同一个Set集合时,需要手动同步该Set集合。

    通常可通过Collections工具类的静态方法synchronizedXxx()来同步集合。

  • 相关阅读:
    排序算法分析
    Android学习之DragEvent
    Android Studio导出Jar包
    Android中的一些基础知识(三)
    Android中的一些基础知识(一)
    Android中的一些基础知识(二)
    Android学习之Drawable(一)
    Android消息机制之Handler
    Android滑动事件冲突
    Android创建窗口(一)创建应用窗口
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/10890247.html
Copyright © 2011-2022 走看看