Set 简介
Set 和 List 一样,也是继承 Collection 接口, Set 不保存重复的元素,如果试图将相同对象的多个实例添加到 Set 中,那么不好意思,它会立马阻止。Set 判断两个对象是否相同,使用的是 equals() 方法,只要该方法的结果是 true,Set 就不会接收这个对象。
Set 具有和 Collection 完全一样的接口,因此没有任何额外的功能,实际上 Set 就是 Collection,只是行为不同,Set 是基于对象的值来确定归属性的。它最常用的实现类就是 HashSet 和 TreeSet。
HashSet
HashSet 是无序的,不能保证元素的排列顺序,下面是一段示例代码:
public class SetTest {
public static void main(String[] args) {
//创建 set 对象,参数类型为 Integer
Set<Integer> set = new HashSet<Integer>();
//存放 0 ~ 9 的整数
for (int i = 0; i < 10; i++) {
set.add(i);
}
for (Integer i : set) {
System.out.println("元素" + s + "的 hashcode 值:" + s.hashCode());
}
}
}
打印结果是啥?大家可以猜猜结果。
先说说 HashSet 的存放规则,当向 HashSet 中存放一个元素的时候,HashSet 会调用对象的 hashcode() 方法来得到该对象的 hashcode 值,然后根据 hashcode 值来决定该对象在 HashSet 中的存储位置。上面代码的结果如下:
元素0的 hashcode 值:0
元素1的 hashcode 值:1
元素2的 hashcode 值:2
元素3的 hashcode 值:3
元素4的 hashcode 值:4
元素5的 hashcode 值:5
元素6的 hashcode 值:6
元素7的 hashcode 值:7
元素8的 hashcode 值:8
元素9的 hashcode 值:9
整数元素会根据其散列值的顺序排列,如果元素不是整数,而是字符串呢?
public static void main(String[] args) {
//创建 set 对象,参数类型为 String
Set<String> set = new HashSet<>();
set.add("cat");
set.add("tom");
set.add("sam");
for (String s : set) {
System.out.println("元素" + s + "的 hashcode 值:" + s.hashCode());
}
}
打印结果:
元素tom的 hashcode 值:115026
元素cat的 hashcode 值:98262
元素sam的 hashcode 值:113631
很明显,结果是无序的。请牢记 HashSet 是无序集合,使用的时候就不该考虑顺序。如果想让结果有序,那么可以使用 TreeSet。
TreeSet
TreeSet 将元素存储在红黑树(平衡二叉树)结构中,而 HashSet 使用的是散列函数。TreeSet 不仅能保证元素的唯一性,还能对元素按照某种规则进行排序,排序有两种:自然排序和定制排序。
先看看自然排序:
public static void main(String[] args) {
//创建 set 对象,参数类型为 String
Set<String> set = new TreeSet<>();
set.add("cat");
set.add("tom");
set.add("sam");
for (String s : set) {
System.out.println(s);
}
}
打印结果:
cat
sam
tom
可以看到结果是按照字母进行自然排序的,自然排序需要使用元素的 CompareTo() 方法来得到元素之间的大小关系,然后按升序排列。 obj1.compareTo(obj2) 方法如果返回 0,则说明被比较的两个对象相等,如果返回一个正数,则表明 obj1 大于 obj2,如果是负数,则表明 obj1 小于 obj2。
下面瞅瞅定制排序:
public static void main(String[] args) {
//创建 set 对象,传入一个 Comparator 对象
Set<String> set = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//倒序
return o2.compareTo(o1);
}
});
set.add("cat");
set.add("tom");
set.add("sam");
for (String s : set) {
System.out.println(s);
}
}
打印结果:
tom
sam
cat
结果如期而至,倒序排列。代码中使用 TreeSet 的有参构造器:TreeSet(Comparator<? super E> comparator),以匿名内部类的方式传入一个 Comparator 对象,并实现其中的 compare() 方法来指定排序规则。
小结
本文介绍了 Set 和其两个常见的实现类 HashSet 和 TreeSet,Set 中元素都是唯一的,可以存放 null,但是只能存一个,HashSet 不保证元素的顺序,TreeSet 中的元素是有序的,默认是自然排序,可以根据业务进行定制排序。