Java 中的 HashSet,内部是如何工作的?
2017-12-26 13:56
316 查看
继续分享一道Java经典面试题:
题目描述:
Java 中的 HashSet,内部是如何工作的?
HashSet 的内部采用 HashMap来实现。由于 Map 需要 key 和 value,所以HashSet中所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个null key,意思就是 HashSet 中只允许存储一个 null 对象。
答案过于简单 对于Java中的HashSet的实现原理进一步的探索 得到了这些知识,分享给大家:
HashSet:
实现了Set接口
HashSet依赖的数据结构是哈希表
因为实现的是Set接口,所以不允许有重复的值
插入到HashSet中的对象不保证与插入的顺序保持一致。对象的插入是根据它的hashcode
HashSet中允许有NULL值
HashSet也实现了Searlizable和Cloneable两个接口
HashSet的构造函数:
2
3
4
5
6
7
8
9
什么是初始化大小与装载因子:
初始化尺寸就是当创建哈希表(HashSet内部用哈希表的数据结构)的时候桶(buckets)的数量。如果当前的尺寸已经满了,那么桶的数量会自动增长。
装载因子衡量的是在HashSet自动增长之前允许有多满。当哈希表中实体的数量已经超出装载因子与当前容量的积,那么哈希表就会再次进行哈希(也就是内部数据结构重建),这样哈希表大致有两倍桶的数量。
2
3
例如:如果内部容量为16,装载因子为0.75,那么当表中有12个元素的时候,桶的数量就会自动增长。
性能影响:
装载因子和初始化容量是影响HashSet操作的两个主要因素。装载因子为0.75的时候可以提供关于时间和空间复杂度方面更有效的性能。如果我们加大这个装载因子,那么内存的上限就会减小(因为它减少了内部
f3b8
重建的操作),但是将影响哈希表中的add与查询的操作。为了减少再哈希操作,我们应该选择一个合适的初始化大小。如果初始化容量大于实体的最大数量除以装载因子,那么就不会有再哈希的动作发生了。
HashSet中的一些重要方法:
boolean add(E e):如果不存在则添加,存在则返回false。
void clear() :移除Set中所有的元素
boolean contains(Object o):如果这个元素在set中存在,那么返回true。
boolean remove(Object o):如果这个元素在set中存在,那么从set中删除。
Iterator iterator():返回set中这个元素的迭代器。
简单的程序:
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
上述代码的输出:
2
3
4
5
6
HashSet内部是如何工作的?
所有Set接口的类内部都是由Map做支撑的。HashSet用HashMap对它的内部对象进行排序。你一定好奇输入一个值到HashMap,我们需要的是一个键值对,但是我们传给HashSet的是一个值。
那么HashMap是如何排序的?
实际上我们插入到HashSet中的值在map对象中起的是键的作用,因为它的值Java用了一个常量。所以在键值对中所有的键的值都是一样的。
如果我们在Java Doc中看一下HashSet的实现,大致是这样的:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
如果我们看下HashSet中的add方法:
2
3
4
我们可以注意到,HashSet类的add()方法内部调用的是HashMap的put()方法,通过你指定的值作为key,常量“PRESENT”作为值传过去。
remove()也是用类似的方法工作。它内部调用的是Map接口的remove。
2
3
4
HashSet操作的时间复杂度:
HashSet底层的数据结构是哈希表,所以HashSet的add,remove与查询(包括contain方法)的分摊(平均或者一般情况)时间复杂度是O(1)。
参考文献:
https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html
http://blog.csdn.net/sinat_36246371/article/details/53366104
题目描述:
Java 中的 HashSet,内部是如何工作的?
HashSet 的内部采用 HashMap来实现。由于 Map 需要 key 和 value,所以HashSet中所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个null key,意思就是 HashSet 中只允许存储一个 null 对象。
答案过于简单 对于Java中的HashSet的实现原理进一步的探索 得到了这些知识,分享给大家:
HashSet:
实现了Set接口
HashSet依赖的数据结构是哈希表
因为实现的是Set接口,所以不允许有重复的值
插入到HashSet中的对象不保证与插入的顺序保持一致。对象的插入是根据它的hashcode
HashSet中允许有NULL值
HashSet也实现了Searlizable和Cloneable两个接口
HashSet的构造函数:
HashSet h = new HashSet(); 默认初始化大小是16,默认装载因子是0.75. HashSet h = new HashSet(int initialCapacity); 默认装载因子是0.75 HashSet h = new HashSet(int initialCapacity, float loadFactor); HashSet h = new HashSet(Collection C);1
2
3
4
5
6
7
8
9
什么是初始化大小与装载因子:
初始化尺寸就是当创建哈希表(HashSet内部用哈希表的数据结构)的时候桶(buckets)的数量。如果当前的尺寸已经满了,那么桶的数量会自动增长。
装载因子衡量的是在HashSet自动增长之前允许有多满。当哈希表中实体的数量已经超出装载因子与当前容量的积,那么哈希表就会再次进行哈希(也就是内部数据结构重建),这样哈希表大致有两倍桶的数量。
表中已经存储的元素的数量 装载因子 = ----------------------------------------- 哈希表的大小1
2
3
例如:如果内部容量为16,装载因子为0.75,那么当表中有12个元素的时候,桶的数量就会自动增长。
性能影响:
装载因子和初始化容量是影响HashSet操作的两个主要因素。装载因子为0.75的时候可以提供关于时间和空间复杂度方面更有效的性能。如果我们加大这个装载因子,那么内存的上限就会减小(因为它减少了内部
f3b8
重建的操作),但是将影响哈希表中的add与查询的操作。为了减少再哈希操作,我们应该选择一个合适的初始化大小。如果初始化容量大于实体的最大数量除以装载因子,那么就不会有再哈希的动作发生了。
HashSet中的一些重要方法:
boolean add(E e):如果不存在则添加,存在则返回false。
void clear() :移除Set中所有的元素
boolean contains(Object o):如果这个元素在set中存在,那么返回true。
boolean remove(Object o):如果这个元素在set中存在,那么从set中删除。
Iterator iterator():返回set中这个元素的迭代器。
简单的程序:
// Java program to demonstrate working of HashSet import java.util.*; class Test { public static void main(String[]args) { HashSet<String> h = new HashSet<String>(); // adding into HashSet h.add("India"); h.add("Australia"); h.add("South Africa"); h.add("India");// adding duplicate elements // printing HashSet System.out.println(h); System.out.println("List contains India or not:" + h.contains("India")); // Removing an item h.remove("Australia"); System.out.println("List after removing Australia:"+h); // Iterating over hash set items System.out.println("Iterating over list:"); Iterator<String> i = h.iterator(); while (i.hasNext()) System.out.println(i.next()); } }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
上述代码的输出:
[Australia, South Africa, India] List contains India or not:true List after removing Australia:[South Africa, India] Iterating over list: South Africa India1
2
3
4
5
6
HashSet内部是如何工作的?
所有Set接口的类内部都是由Map做支撑的。HashSet用HashMap对它的内部对象进行排序。你一定好奇输入一个值到HashMap,我们需要的是一个键值对,但是我们传给HashSet的是一个值。
那么HashMap是如何排序的?
实际上我们插入到HashSet中的值在map对象中起的是键的作用,因为它的值Java用了一个常量。所以在键值对中所有的键的值都是一样的。
如果我们在Java Doc中看一下HashSet的实现,大致是这样的:
private transient HashMap map; // Constructor - 1 // All the constructors are internally creating HashMap Object. public HashSet() { // Creating internally backing HashMap object map = new HashMap<>(); } // Constructor - 2 public HashSet(int initialCapacity) { // Creating internally backing HashMap object map = new HashMap<>(initialCapacity); } // Dummy value to associate with an Object in Map private static final Object PRESENT = new Object();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
如果我们看下HashSet中的add方法:
public boolean add(E e) { return map.put(e, PRESENT) == null; }1
2
3
4
我们可以注意到,HashSet类的add()方法内部调用的是HashMap的put()方法,通过你指定的值作为key,常量“PRESENT”作为值传过去。
remove()也是用类似的方法工作。它内部调用的是Map接口的remove。
public boolean remove(Object o) { return map.remove(o) == PRESENT; }1
2
3
4
HashSet操作的时间复杂度:
HashSet底层的数据结构是哈希表,所以HashSet的add,remove与查询(包括contain方法)的分摊(平均或者一般情况)时间复杂度是O(1)。
参考文献:
https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html
http://blog.csdn.net/sinat_36246371/article/details/53366104
相关文章推荐
- 栈(stack)与堆(heap)区别以及Java的string变量赋值的内部工作机制(精典转载贴)
- 请问在北京如何找java程序员的工作 我在招聘网上发了简历都没有人回
- 第2章 Java编程基础——FAQ2.20 “+”操作符在Java内部是如何实现字符串连接的?
- Java垃圾回收器如何工作
- Java中的垃圾回收是如何工作的?(How Garbage Collection works in Java)
- struts2 src study 准备工作 和 略谈 如何读开源代码(Java)
- 栈(stack)与堆(heap)区别以及Java的string变量赋值的内部工作机制(精典转载贴)
- 如何顺利找到Java高级程序员的工作
- [转自360kr]如何才能进入Facebook工作?公司内部工程师告诉你
- 如何才能进入Facebook工作?公司内部工程师告诉你
- Java中如何克服"构造器只能使初始化工作进行一次"的"缺点"?
- Java 虚拟机是如何工作的
- Java中HashMap如何工作的?
- JavaIO——java如何读取jar包自身内部的属性文件
- 栈(stack)与堆(heap)区别以及Java的string变量赋值的内部工作机制(精典转载贴)
- java基础---->垃圾回收器如何工作
- Java Web服务器都是如何工作的
- 关于Unity内部脚本如何工作的简单概览
- java新手如何找 工作啊?
- 第1章 Java基本概念及环境配置——FAQ1.07 什么是JVM?有什么作用?工作机制如何?