Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较
Writer:BYSocket(泥沙砖瓦浆木匠)
微博:BYSocket
豆瓣:BYSocket
上一篇总结了下ArrayList 、LinkedList和Vector比较,今天泥瓦匠总结下Hash 、LinkedList和Vector比较。其实大家都是Collection,只不过有点各自特性。那就是数据结构的不同表现。
一、Set回顾
一个不包括重复元素(包括可变对象)的Collection,是一种无序的集合。Set不包含满 a.equals(b) 的元素对a和b,并且最多有一个null。
泥瓦匠的记忆宫殿:
1、不允许包含相同元素
2、判断对象是否相同,根据equals方法
![]()
二、HashSet
一个按着Hash算法来存储集合中的元素,其元素值可以是NULL。它不能保证元素的排列顺序。同样,HashSet是不同步的,如果需要多线程访问它的话,可以用 Collections.synchronizedSet 方法来包装它:
|
1
|
Set s = Collections.synchronizedSet(new HashSet(...)); |
同上一节一样,用迭代器的时候,也要注意 并发修改异常ConcurrentModificationException。
要注意的地方是,HashSet集合判断两个元素相等不单单是equals方法,并且必须hashCode()方法返回值也要相等。看下面的例子:
|
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
38
39
40
41
42
43
44
45
46
47
|
import java.util.HashSet;class EuqalsObj{ public boolean equals(Object obj) { return true; }}class HashCodeObj{ public int hashCode() { return 1; }}class HashSetObj{ public int hashCode() { return 2; } public boolean equals(Object obj) { return true; }}public class HashSetTest{ public static void main(String[] args) { HashSet objs = new HashSet(); objs.add(new EuqalsObj()); objs.add(new EuqalsObj()); objs.add(new HashCodeObj()); objs.add(new HashCodeObj()); objs.add(new HashSetObj()); objs.add(new HashSetObj()); System.out.println("HashSet Elements:"); System.out.print("\t" + objs + "\n"); }} |
Run 一下,控制台如下输出:
|
1
2
|
HashSet Elements: [HashCodeObj@1, HashCodeObj@1, HashSetObj@2, EuqalsObj@1471cb25, EuqalsObj@3acff49f] |
泥瓦匠根据结果,一一到来。首先,排列顺序不定。
HashSetObj 类满足我们刚刚的要求,所以集合中只有一个且它的HashCode值为2。
HashCodeObj 类虽然它们HashCode值为1,但是他们不相等。(其实当HashCode值一样,这个存储位置会采用链式结构保存两个HashCodeObj对象。)
同样,EqualsObj 类他们相等,但是他们HashCode值不等,分别为1471cb25、3acff49f。
因此,用HashSet添加可变对象,要注意当对象有可能修改后和其他对象矛盾,这样我们无法从HashSet找到准确我们需要的对象。
三、LinkedHashList
HashSet的子类,也同样有HashCode值来决定元素位置。但是它使用链表维护元素的次序。记住两个字:有序。
有序的妙用,复制。比如泥瓦匠实现一个HashSet无序添加,然后复制一个一样次序的HashSet来。代码如下:
|
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
|
package com.sedion.bysocket.collection;import java.util.HashSet;import java.util.LinkedHashSet;import java.util.Set;public class LinkedHashListTest{ public static void main(String[] args) { /* 复制HashSet */ Set h1 = new HashSet<String>(); h1.add("List"); h1.add("Queue"); h1.add("Set"); h1.add("Map"); System.out.println("HashSet Elements:"); System.out.print("\t" + h1 + "\n"); Set h2 = copy(h1); System.out.println("HashSet Elements After Copy:"); System.out.print("\t" + h2 + "\n"); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static Set copy(Set set) { Set setCopy = new LinkedHashSet(set); return setCopy; } } |
Run 一下,控制台输出:
|
1
2
3
4
|
HashSet Elements: [Map, Queue, Set, List]HashSet Elements After Copy: [Map, Queue, Set, List] |
可见,每个数据结构都有它存在的理由。
四、TreeSet
TreeSet使用树结构实现(红黑树),集合中的元素进行排序,但是添加、删除和包含的算法复杂度为O(log(n))。
举个例子吧,首先我们定义一个Bird类。(鸟是泥瓦匠最喜欢的动物)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Bird{ int size; public Bird(int s) { size = s; } public String toString() { return size + ""; }} |
然后用TreeSet添加Bird类。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class TreeSetTest{ public static void main(String[] args) { TreeSet<Bird> bSet = new TreeSet<Bird>(); bSet.add(new Bird(1)); bSet.add(new Bird(3)); bSet.add(new Bird(2)); Iterator<Bird> iter = bSet.iterator(); while (iter.hasNext()) { Bird bird = (Bird) iter.next(); System.out.println(bird); } }} |
Run一下,控制台输出如下:
|
1
2
3
4
5
|
Exception in thread "main" java.lang.ClassCastException: Bird cannot be cast to java.lang.Comparable at java.util.TreeMap.compare(Unknown Source) at java.util.TreeMap.put(Unknown Source) at java.util.TreeSet.add(Unknown Source) at com.sedion.bysocket.collection.TreeSetTest.main(TreeSetTest.java:29) |
答案很明显,TreeSet是排序的。所以Bird需要实现Comparable此接口。
java.lang.Comparable此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
修改Bird如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Bird implements Comparable<Bird>{ int size; public Bird(int s) { size = s; } public String toString() { return size + "号鸟"; } @Override public int compareTo(Bird o) { return size - o.size; } } |
再次Run一下:
|
1
2
3
|
1号鸟2号鸟3号鸟 |
五、性能测试比较
针对上面三种Set集合,我们对它们的Add方法进行性能测试:
|
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
import java.util.HashSet;import java.util.LinkedHashSet;import java.util.Random;import java.util.TreeSet;class Bird implements Comparable<Bird>{ int size; public Bird(int s) { size = s; } public String toString() { return size + "号鸟"; } @Override public int compareTo(Bird o) { return size - o.size; } }public class Set{ public static void main(String[] args) { Random r = new Random(); HashSet<Bird> hashSet = new HashSet<Bird>(); TreeSet<Bird> treeSet = new TreeSet<Bird>(); LinkedHashSet<Bird> linkedSet = new LinkedHashSet<Bird>(); // start time long startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { int x = r.nextInt(1000 - 10) + 10; hashSet.add(new Bird(x)); } // end time long endTime = System.nanoTime(); long duration = endTime - startTime; System.out.println("HashSet: " + duration); // start time startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { int x = r.nextInt(1000 - 10) + 10; treeSet.add(new Bird(x)); } // end time endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("TreeSet: " + duration); // start time startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { int x = r.nextInt(1000 - 10) + 10; linkedSet.add(new Bird(x)); } // end time endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("LinkedHashSet: " + duration); }} |
Run一下,可以在控制台中看出:
|
1
2
3
|
HashSet: 2610998TreeSet: 3195378LinkedHashSet: 2673782 |
可见,TreeSet因为需要进行比较,所以性能比较差。
六、总结
HashSet:equlas hashcode
LinkedHashSet:链式结构
TreeSet:比较,Comparable接口,性能较差
Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较的更多相关文章
- Java 容器 & 泛型:五、HashMap 和 TreeMap的自白
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...
- Java容器深入浅出之HashSet、TreeSet和EnumSet
Java集合中的Set接口,定义的是一类无顺序的.不可重复的对象集合.如果尝试添加相同的元素,add()方法会返回false,同时添加失败.Set接口包括3个主要的实现类:HashSet.TreeSe ...
- Java 容器 & 泛型:一、认识容器
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 容器是Java语言学习中重要的一部分.泥瓦匠我的感觉是刚开始挺难学的,但等你熟悉它,接触多了,也就“顺 ...
- HashSet,TreeSet和LinkedHashSet的区别
Set接口Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false.Set判断两个对象相同不是使用==运算符,而是根据equals方法.也就是说,只要两个对象用eq ...
- Set下面HashSet,TreeSet和LinkedHashSet的区别
Set接口Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false.Set判断两个对象相同不是使用==运算符,而是根据equals方法.也就是说,只要两个对象用eq ...
- HashSet,TreeSet和LinkedHashSet
Set接口 Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false. Set判断两个对象相同不是使用==运算符,而是根据equals方法.也就是说,只要两个对象用 ...
- Java 容器 & 泛型:六、容器讲到为什么要使用泛型
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket ArrayList是集合类中无处不在的,泛型也是,泛型对集合类尤其有用.但是为啥要使用泛型?理解好了这 ...
- Java 容器 & 泛型:四、Colletions.sort 和 Arrays.sort 的算法
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 本来准备讲 Map集合 ,还是喜欢学到哪里总结吧.最近面试期准备准备,我是一员,成功被阿里在线笔试秒杀 ...
- Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比较
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 继续上一篇的容器文章认识容器,泥瓦匠慢慢带你们走进List的容器解说.今天泥瓦匠想说说 ArrayLi ...
随机推荐
- vim编辑器中没有高亮显示,退格键不能使用的问题
在~/.vimrc下添加如下内容,立即生效
- arduino 引脚作为输入时的不稳定 解决方案
问题描述: arduino引脚作为输入状态时,高低电平不稳定 出现的原因: arduino 引脚为输入时,引脚电平处于悬空状态,容易受外部电荷信号等干扰 解决的方案: 再程序配置为输入状态后 使用下拉 ...
- JQuery跳出each循环的方法
一.jquery each循环,要实现break和continue的功能: break----用return false; continue --用return ture; 二.jquery怎么跳出当 ...
- 在JAVA中对于类,对象,继承,多态的看法
这是我第一次学高级语言.很抱歉选择了JAVA,目标是开发一款可以上线的APP. 类:是建立对象的一个模板,就是系列产品中的基础款图纸.只是图纸而已.不是产品. 对象:是一个可以操作的对象.新建一个对象 ...
- C pointer again …
记录一个比较基础的东东…… C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...
- centos jdk 配置及版本切换
一. 环境变量: /etc/profile JAVA_HOME=/usr/lib/jdk1.8.0_91JRE_HOME=/usr/lib/jdk1.8.0_91/jreCLASS_PATH=.:$J ...
- socket的阻塞与非阻塞,同步与非同步
网络编程中通常提到四种方式,同步/异步,阻塞/非阻塞.以下对它们的概念进行总结 1.同步/异步:主要针对C端 同步:所谓同步,就是在C端发出一个功能调用时,在没有得到结果之前,调用不返回,也就是必须一 ...
- python Descriptor (描述符)
简介: python 描述符是新式类(继承自object)中的语言协议,基于描述符可以提供更佳优雅的解决方案. python的classmethod, staticmethod, property都是 ...
- 探秘JS的异步单线程
对于通常的developer(特别是那些具备并行计算/多线程背景知识的developer)来讲,js的异步处理着实称得上诡异.而这个诡异从结果上讲,是由js的“单线程”这个特性所导致的. 我曾尝试用“ ...
- 逆水行舟 —— MyBatis
第一轮总结性笔记 这是一个很漫长的过程,我买了套课程,将在日后记录学习笔记,取名为逆水行舟系列 MyBatis的基础 根据MyBatis的官方介绍: 整个测试项目结构如下:使用Maven架构项目 po ...