Set集合

2019-05-22 06:29:32来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

 

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()来同步集合。

 


原文链接:https://www.cnblogs.com/chy18883701161/p/10890247.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:用JQ实现基础的添加,插入,删除功能。

下一篇:JSTL标签库