集合(3)—— Set

一、什么是Set?

Set接口是Collection接口的子接口,是一种不允许重复元素的集合。

 

二、HashSet

  • HashSet是Set的一个典型实现类,无序,不可重复,允许加入NULL,大多数时候使用Set就是使用这个类,HashSet按照Hash算法来存储元素,因此具备很好的存取和查找性能。
  • 其底层其实是一个数组,存在的意义是加快查询速度,我们知道一般的数组,元素在其中的索引位置都是随机的,元素的取值和位置之间没有关联关系,因此,在数组中查找特定的元素时,只能逐个比较,查找速度取决于比较的次数。但是在HashSet底层的数组中,索引和值之间存在确定的关系:index=hash(value),因此通过这个关系可以快速的找到元素或者索引。
  • 当在HashSet中存储元素时,首先调用该对象的hashCode()方法,获取hashCode值,根据这个值,找到对应位置,HashSet中不允许重复,判断方法是:先比较hashCode是否相同,不同就认为是不同对象,相同的话再比较equals方法,根据结果判断。
  • 每一个存储到哈希表中的对象,都要提供equals方法和hashCode方法实现,以判断是否是相同对象,对于HashSet,我们应该保证如果两个对象通过equals方法返回true,hashCode值也相同。

 

 

三、LinkedHashSet

LinkedHashSet是有序,不允许重复,允许加入NULL的集合。

它也是以HashCode值来决定元素的存储位置,同时还使用了链表来维护元素的顺序,这就使得它按照插入的顺序有序排列。相比Hashset多维护了链表,因此性能略低于HashSet。

 

四、TreeSet

TreeSet是有序,不允许重复,不允许NULL的集合。底层使用红黑树算法,擅长范围查询。

  • 如果使用TreeSet的无参构造器新建一个TreeSet对象,要求存储其中的元素实现Comparable接口,所以在其中不能存入NULL
  • 必须存入相同类型的对象(默认会进行排序),否则会出现类型转换异常!一般使用泛型来进行限制。
  • 自然排序:要求被添加的参数对象必须实现Comparable接口,并且覆盖了compareTo(Object obj)方法:

  如果 this>obj ,返回1,

  如果 this=obj ,返回0,

  如果 this<obj ,返回-1。

  通过该方法定义的规则比较之后,按照升序排列。

  • 定制排序:创建TreeSet对象时,传入实现了Compartor接口的实现类,通过compare方法定义的规则进行定制排序(如倒序),要求该实现类的compare方法和equals方法具有一致性,即:compare方法中,两个对象相等时应该return 0。

如下,按照money多少降序排列:

 1 package com.vi.collection.set;
 2 
 3 import java.util.Comparator;
 4 import java.util.TreeSet;
 5 
 6 public class TreeSetDemo {
 7     public static void main(String[] args) {
 8         Man m1 = new Man(1000);
 9         Man m2 = new Man(2000);
10         Man m3 = new Man(3000);
11         Man m4 = new Man(2500);
12         TreeSet<Man> ts = new TreeSet<>(new Man(0));
13         ts.add(m1);
14         ts.add(m2);
15         ts.add(m3);
16         ts.add(m4);
17         System.out.println(ts);
18     }
19 }
20 
21 class Man implements Comparator<Man> {
22     double money;
23 
24     public int compare(Man m1, Man m2) {
25         if (m2.money > m1.money)
26             return 1;
27         if (m2.money == m1.money)
28             return 0;
29         return -1;
30     }
31 
32     public Man(double money) {
33         this.money = money;
34     }
35 
36     public String toString(){
37         return money+" ";
38     }
39 
40 }
View Code

 

 

 

 

 五、对以上三种Set进行比较

共同点:

1.都不允许存入重复值

2.都是线程不安全的(解决办法:使用Collections.synchronizedSet()方法)

 

不同点:

1.TreeSet不允许NULL值,HashSet和LinkedList可以存入空值

2.HashSet是无序的底层采用哈希表算法,查询效率高,通过equals()和hashCode()共同判断对象是否相等,即要求存入的对象重写equals()和hashCode()保持一致性;

LinkedList底层采用了哈希表和链表的结构,既保证了元素的添加顺序,也保证了查询效率,性能略低于HashSet;

TreeSet不保证元素的添加顺序,但是会按照自然排序或定制规则对集合中元素进行排序,底层采用了红黑树算法(树结构比较适合范围查询)。

 

posted on 2019-10-06 11:18  nameless_vi  阅读(146)  评论(0编辑  收藏  举报

导航