0%

Set 集合

概述

Set 接口继承自 Collection 。Set 接口中没有新增方法,方法和 Collection 保持完全一致。 在 List 学习的方法,在 Set 中仍然适用。

特点

无序、不可重复。无序指 Set 中的元素没有索引。我们只能遍历查找;不可重复指不允许加入重复的元素,更确切地讲,新元素如果和 Set 中某个元素通过 equals() 方法对比为 true , 则不能加入;甚至,Set 中也只能放入一个 null 元素,不能多个。

Set 常用的实现类有: HashSet. TreeSet等 。我们一般使用 HashSet .

HashSet

使用

1
2
3
4
5
6
7
8
9
10
      Set<String> s = new HashSet<>();
s.add("hello");
s.add("world");
System.out.println(s);
s.add("hello");//相同的元素不会加入
System.out.println(s);
s.add(null);
System.out.println(s);
s.add(null);
System.out.println(s);

结果

1
2
3
4
[world, hello]
[world, hello]
[null, world, hello]
[null, world, hello]

底层

HashSet 是采用哈希算法实现,底层实际用来 HashMap 实现的,其实 HashSet 本质就是一个简化版的 HashMap,因此查询和增删效率都比较高,我们看看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable{
......
private transient HashMap<E,Object> map;

private static final Object PRESENT = new Object();

public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
......
}

可以发现里面有个 map 属性,再看看 add() 方法,发现说白了就是在 map 中增加一个键值对,键就是这个元素,值对象是名为 PRESENT 的 Object 对象固定好的。

TreeSet

用法和 HashSet 差不多。只是这个有排序。

底层

TreeSet 底层实际是用 TreeMap 实现的,内部维持了一个简化版的 TreeMap ,通过 key 来存儲 Set 的元素。TreeSet内部需要対存儲的元素迸行排序,因此,我們对应的类需要实现 Comparable 接口。这样,オ能根据 compareTo() 方法比較対象之同的大小。オ能迸行内排序。

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
private transient NavigableMap<E,Object> m;

private static final Object PRESENT = new Object();

TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}

public TreeSet() {
this(new TreeMap<E,Object>());
}
......
}

里面其中一个成员 m 类型是 NavigableMap ,这是一个接口,其中 TreeMap 实现了这个接口,从构造函数可以看出它在生成的时候,马上 new 了 TreeMap 。

Comparable 的使用

和 TreeMap 的用法一样,通过实现 Comparable 接口进行排序。

假设我们要对一个 Employee 类排序,先依照里面的 salary 大小,在依照 id 排序,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 这里接口中的泛型就是自定义的类,比较要跟自己同类比较
class Employee implements Comparable<Employee> {
int id;
String name;
double salary;

public Employee(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}

@Override
public String toString() {
return "id:"+id+",name:"+name+",salary:"+salary;
}
//这里就实现了用于比较自定义类大小的方法
@Override
public int compareTo(Employee o) { //负数:小于,0:等于,正数:大于

if(this.salary>o.salary){
return 1;
}else if(this.salary<o.salary){
return -1;
}else{
if(this.id>o.id){
return 1;
}else if(this.id<o.id){
return -1;
}else{
return 0;
}
}

}
}

本文标题:Set 集合

文章作者:志者

发布时间:2020年01月16日 - 15:50:00

最后更新:2020年01月30日 - 20:45:07

原始链接:http://witman1999.github.io/Set接口.html

许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------
copy