HashMap和HashSet的区别和分析
2016-05-15 17:22
447 查看
HashSet定义
HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。public boolean add(Object o)方法用来在Set中添加元素,当元素值重复时则会立即返回false,如果成功添加的话会返回true。
HashSet构造方法摘要
HashSet()构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
HashSet(Collection<? extends E> c)
构造一个包含指定 collection 中的元素的新 set。
HashSet(int initialCapacity)
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。
HashSet(int initialCapacity, float loadFactor)
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。
<span style="font-size:14px;">/** * 默认构造函数 * 初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。 */ public HashSet() { map = new HashMap<>(); } /** * 构造一个包含指定 collection 中的元素的新 set。 */ public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } /** * 构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子 */ public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } /** * 构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。 */ public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } /** * 在API中我没有看到这个构造函数,今天看源码才发现(原来访问权限为包权限,不对外公开的) * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。 * dummy 为标识 该构造函数主要作用是对LinkedHashSet起到一个支持作用 */ HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }</span>
现在来看一下HashSet的add方法:
// Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
public boolean add(E e) { <span style="color:#ff0000;">return m.put(e, PRESENT)==null;</span> }
正如我们看到的,add方法调用了HashMap的put方法。这里我们看到了之前的成员变量PRESENT,即,我们存入到HashSet的对象作为key传给了map,而我们不关心这个key对应的value,所以才定义了一个静态final的object对象。
m.put(e, PRESENT)==null//这条判断语句<span style="font-family: 宋体, Arial; background-color: rgb(255, 255, 255);">保证集合中元素的唯一性的工作</span>
至此,我们可以大概明白HashSet的实现本质,它封装了一个HashMap。
hashset的其他方法:
public boolean remove(Object o) { return<span style="color:#ff0000;"> map.remove(o)==PRESENT;</span> } public boolean contains(Object o) { return map.containsKey(o); }
public int size() { return map.size(); } /** * Returns <tt>true</tt> if this set contains no elements. * * @return <tt>true</tt> if this set contains no elements */ public boolean isEmpty() { return map.isEmpty(); }
public void clear() { map.clear(); } /** * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements * themselves are not cloned. * * @return a shallow copy of this set */ public Object clone() { try { HashSet<E> newSet = (HashSet<E>) super.clone(); newSet.map = (HashMap<E, Object>) map.clone(); return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(); } }
什么是HashMap(Hashmap的具体细节在前面的博文中有提到,这里就不赘述)
HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许重复的键。Map接口有两个基本的实现,HashMap和TreeMap。TreeMap保存了对象的排列次序,而HashMap则不能。HashMap允许键和值为null。HashMap是非synchronized的。public Object put(Object Key,Object value)方法用来将元素添加到map中。
那么hashMap的工作原理是什么?
当系统开始初始化HashMap的时候,系统会创建一个长度为capacity的Entry数组。这个数组存储的元素是一个系列元素的索引,也称为“桶”,当一个元素要增加的时候,会计算他的hashcode,然后再数组中寻找他的位置,比如,他的位置有元素占据了,那么会在该元素上,扩展出一条索引链,将数据插入到这个索引链上。
HashSet和HashMap的区别
*HashMap* | *HashSet* |
HashMap实现了Map接口 | HashSet实现了Set接口 |
HashMap储存键值对 | HashSet仅仅存储对象 |
使用put()方法将元素放入map中 | 使用add()方法将元素放入set中 |
HashMap中使用键对象来计算hashcode值 | HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false |
HashMap比较快,因为是使用唯一的键来获取对象 | HashSet较HashMap来说比较慢 |
相关文章推荐
- iOS开发系列--无限循环的图片浏览器
- Sql四种语言
- Java编程思想[一]对象
- [Linux][PHP]安装swoole扩展
- 64.GitHub 排名前100的android项目简介
- [PWA] 1. Intro to Service worker
- jquery-uploadfile的使用(多文件异步上传)
- c函数编程之指针参数和指向指针的指针参数
- c语言之被遗漏的角落---#pragma pack
- <<、>>、>>>的运用
- 自定义组件 悬浮球的实现
- php 数据类型与转换
- MySQL存储引擎InnoDB与MyISAM
- 使用 Equinox 开发 OSGi 应用程序
- 利用上面的两个包做的一个不成功的案例
- JavaSE_遍历List的3种方法
- Nonlocal-Means 算法图像去噪
- 微软面试100题-72
- IOS开发调试
- 更新yum 源