• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > Java中的HashSet详解和使用示例_动力节点Java学院整理

Java中的HashSet详解和使用示例_动力节点Java学院整理

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了java hashset,java hashset用法,java hashset遍历,java中hashset,java hashset排序等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

第1部分 HashSet介绍

HashSet 简介

HashSet 是一个没有重复元素的集合。

它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素。

HashSet是非同步的。如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问:
Set s = Collections.synchronizedSet(new HashSet(...));

HashSet通过iterator()返回的迭代器是fail-fast的。 

HashSet的构造函数

// 默认构造函数
public HashSet() 
// 带集合的构造函数
public HashSet(Collection<? extends E> c) 
// 指定HashSet初始容量和加载因子的构造函数
public HashSet(int initialCapacity, float loadFactor) 
// 指定HashSet初始容量的构造函数
public HashSet(int initialCapacity) 
// 指定HashSet初始容量和加载因子的构造函数,dummy没有任何作用
HashSet(int initialCapacity, float loadFactor, boolean dummy) 
</div>

HashSet的主要API 

boolean   add(E object)
void   clear()
Object   clone()
boolean   contains(Object object)
boolean   isEmpty()
Iterator<E>  iterator()
boolean   remove(Object object)
int    size() 
</div>

第2部分 HashSet数据结构

HashSet的继承关系如下: 

java.lang.Object
  java.util.AbstractCollection<E>
    java.util.AbstractSet<E>
     java.util.HashSet<E>
public class HashSet<E>
 extends AbstractSet<E>
 implements Set<E>, Cloneable, java.io.Serializable { } 
</div>

HashSet与Map关系如下图:

 从图中可以看出:

(01) HashSet继承于AbstractSet,并且实现了Set接口。

(02) HashSet的本质是一个"没有重复元素"的集合,它是通过HashMap实现的。HashSet中含有一个"HashMap类型的成员变量"map,HashSet的操作函数,实际上都是通过map实现的。

第3部分 HashSet源码解析(基于JDK1.6.0_45)

为了更了解HashSet的原理,下面对HashSet源码代码作出分析。 

 package java.util;
 public class HashSet<E>
  extends AbstractSet<E>
  implements Set<E>, Cloneable, java.io.Serializable
 {
  static final long serialVersionUID = -5024744406713321676L;
   // HashSet是通过map(HashMap对象)保存内容的
  private transient HashMap<E,Object> map;
  // PRESENT是向map中插入key-value对应的value
  // 因为HashSet中只需要用到key,而HashMap是key-value键值对;
  // 所以,向map中添加键值对时,键值对的值固定是PRESENT
  private static final Object PRESENT = new Object();
  // 默认构造函数
  public HashSet() {
   // 调用HashMap的默认构造函数,创建map
   map = new HashMap<E,Object>();
  }
  // 带集合的构造函数
  public HashSet(Collection<? extends E> c) {
   // 创建map。
   // 为什么要调用Math.max((int) (c.size()/.75f) + 1, 16),从 (c.size()/.75f) + 1 和 16 中选择一个比较大的树呢?  
   // 首先,说明(c.size()/.75f) + 1
   // 因为从HashMap的效率(时间成本和空间成本)考虑,HashMap的加载因子是0.75。
   // 当HashMap的“阈值”(阈值=HashMap总的大小*加载因子) < “HashMap实际大小”时,
   // 就需要将HashMap的容量翻倍。
   // 所以,(c.size()/.75f) + 1 计算出来的正好是总的空间大小。
   // 接下来,说明为什么是 16 。
   // HashMap的总的大小,必须是2的指数倍。若创建HashMap时,指定的大小不是2的指数倍;
   // HashMap的构造函数中也会重新计算,找出比“指定大小”大的最小的2的指数倍的数。
   // 所以,这里指定为16是从性能考虑。避免重复计算。
   map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
   // 将集合(c)中的全部元素添加到HashSet中
   addAll(c);
  }
  // 指定HashSet初始容量和加载因子的构造函数
  public HashSet(int initialCapacity, float loadFactor) {
   map = new HashMap<E,Object>(initialCapacity, loadFactor);
  }
  // 指定HashSet初始容量的构造函数
  public HashSet(int initialCapacity) {
   map = new HashMap<E,Object>(initialCapacity);
  }
  HashSet(int initialCapacity, float loadFactor, boolean dummy) {
   map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
  }
  // 返回HashSet的迭代器
  public Iterator<E> iterator() {
   // 实际上返回的是HashMap的“key集合的迭代器”
   return map.keySet().iterator();
  }
  public int size() {
   return map.size();
  }
  public boolean isEmpty() {
   return map.isEmpty();
  }
  public boolean contains(Object o) {
   return map.containsKey(o);
  }
  // 将元素(e)添加到HashSet中
  public boolean add(E e) {
   return map.put(e, PRESENT)==null;
  }
  // 删除HashSet中的元素(o)
  public boolean remove(Object o) {
   return map.remove(o)==PRESENT;
  }
  public void clear() {
   map.clear();
  }
  // 克隆一个HashSet,并返回Object对象
  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();
   }
  }
  // java.io.Serializable的写入函数
  // 将HashSet的“总的容量,加载因子,实际容量,所有的元素”都写入到输出流中
  private void writeObject(java.io.ObjectOutputStream s)
   throws java.io.IOException {
   // Write out any hidden serialization magic
   s.defaultWriteObject();
   // Write out HashMap capacity and load factor
   s.writeInt(map.capacity());
   s.writeFloat(map.loadFactor());
   // Write out size
   s.writeInt(map.size());
   // Write out all elements in the proper order.
   for (Iterator i=map.keySet().iterator(); i.hasNext(); )
    s.writeObject(i.next());
  }
  // java.io.Serializable的读取函数
  // 将HashSet的“总的容量,加载因子,实际容量,所有的元素”依次读出
  private void readObject(java.io.ObjectInputStream s)
   throws java.io.IOException, ClassNotFoundException {
   // Read in any hidden serialization magic
   s.defaultReadObject();
   // Read in HashMap capacity and load factor and create backing HashMap
   int capacity = s.readInt();
   float loadFactor = s.readFloat();
   map = (((HashSet)this) instanceof LinkedHashSet ?
    new LinkedHashMap<E,Object>(capacity, loadFactor) :
    new HashMap<E,Object>(capacity, loadFactor));
   // Read in size
   int size = s.readInt();
   // Read in all elements in the proper order.
   for (int i=; i<size; i++) {
    E e = (E) s.readObject();
    map.put(e, PRESENT);
   }
  }
 }
</div>

说明: HashSet的代码实际上非常简单,通过上面的注释应该很能够看懂。它是通过HashMap实现的,若对HashSet的理解有困难,建议先学习以下HashMap;学完HashMap之后,在学习HashSet就非常容易了。 

第4部分 HashSet遍历方式

4.1 通过Iterator遍历HashSet

第一步:根据iterator()获取HashSet的迭代器。

第二步:遍历迭代器获取各个元素。

// 假设set是HashSet对象
for(Iterator iterator = set.iterator();
  iterator.hasNext(); ) { 
 iterator.next();
} 
</div>

4.2 通过for-each遍历HashSet

第一步:根据toArray()获取HashSet的元素集合对应的数组。

第二步:遍历数组,获取各个元素。

// 假设set是HashSet对象,并且set中元素是String类型
String[] arr = (String[])set.toArr



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Java中的HashSet详解和使用示例_动力节点Java学院整理
  • Java中HashSet和HashMap的区别_动力节点Java学院整理
  • Java中的HashSet详解和使用示例_动力节点Java学院整理
  • Java中HashSet和HashMap的区别_动力节点Java学院整理

相关文章

  • 2017-05-28零基础入门学习——Spring Boot注解(一)
  • 2017-05-28Linux下用java -jar运行可执行jar包的方法教程
  • 2017-05-28Java中使用fileupload组件实现文件上传功能的实例代码
  • 2017-05-28java 中 System.out.println()和System.out.write()的区别
  • 2017-05-28JAVA中ListIterator和Iterator详解与辨析(推荐)
  • 2017-05-28javamail实现注册激活邮件
  • 2017-05-28java基于反射得到对象属性值的方法
  • 2017-05-28Java中的super关键字_动力节点Java学院整理
  • 2017-05-28Java容器HashMap与HashTable详解
  • 2018-08-06Java线程实现抽奖

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Spring Boot 使用Druid详解
    • 详解获取Spring MVC中所有RequestMapping以及对应方法和参数
    • 关于Spring3 + Mybatis3整合时多数据源动态切换的问题
    • Java中ArrayList和LinkedList之间的区别_动力节点Java学院整理
    • Java高级特性(基础)
    • response.setHeader各种用法详解
    • 深入学习Java之PriorityQueue
    • 详解Spring Data操作Redis数据库
    • interrupt()和线程终止方式_动力节点Java学院整理
    • PipedWriter和PipedReader源码分析_动力节点Java学院整理

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有