`
yuanc00
  • 浏览: 29341 次
社区版块
存档分类
最新评论

Java HashSet 源代码学习

    博客分类:
  • java
 
阅读更多

 

 

注:这里使用Java 1.6版本

Set集合,是collection容器的一种;特点是保证里面的元素只出现一次。

 

1.HashSet继承AbstractSet类,实现Set、Cloneable、Serializable接口;

 

2.HashSet的内部实现。

    HashSet内部采用HashMap的方式进行实现。

 

    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

 

 

    HashSet内部采用HashMap进行实现,HashMap中的Key即是Set中的元素;value都是一样的,即上面定义的PRESENT,这是一个Object对象

 

3.HashSet的初始化

    HashSet定义了5种初始化方法:

1)Public HashSet()

    使用不带参数的HashMap的初始化方法,初始化内部的map对象;

 

2)Public HashSet(Collection<? Extends E> c)

    使用collection c进行初始化;先是使用c的元素数量初始化map,(这里使用了HashMap中的扩展因子loadFactor以及阈值的概念,同时默认最小的map大小为16,这也是和HashMap有很深的关系);然后将c中的所有元素加入map中。

 

    /**
     * Constructs a new set containing the elements in the specified
     * collection.  The <tt>HashMap</tt> is created with default load factor
     * (0.75) and an initial capacity sufficient to contain the elements in
     * the specified collection.
     *
     * @param c the collection whose elements are to be placed into this set
     * @throws NullPointerException if the specified collection is null
     */
    public HashSet(Collection<? extends E> c) {
	map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
	addAll(c);
    }

 

 

    addAll方法的实现如下:

 

    public boolean addAll(Collection<? extends E> c) {
	boolean modified = false;
	Iterator<? extends E> e = c.iterator();
	while (e.hasNext()) {
	    if (add(e.next()))
		modified = true;
	}
	return modified;
    }

 

 

    这里使用c的迭代器,将每个c中的元素加入到HashSet中;只要有一个加入成功,整个方法就算成功了。这里的addAll方法,属于AbstractCollection中定义的。

 

    public boolean add(E e) {
	return map.put(e, PRESENT)==null;
    }

 

 

    这里调用的add方法,是HashSet中定义的;加入的时候,设置key为元素e,value为定义好的Object对象PRESENT。当加入成功之后,返回true;加入失败的时候,返回false。这里的加入失败,不是因为操作真正失败了,而是因为元素e已经存在在了HashSet中

 

    这里的实现,通过HashMap实现。在HashMap中,当put一个元素的时候,返回的结果是原始的旧的结果;所以在这里,put的时候,如果元素返回结果是null,表示HashMap中不存在以e为key的元素,即元素e不在HashSet中;如果返回结果不是null,那肯定是PRESENT,表示元素e已经存在了。

 

    同时,向HashMap中put元素,为了返回旧的值;将会先查询HashMap中的结果,这里如果碰撞比较严重(大多数元素的hash结果都相同),也会有性能的问题。一般情况下,不会太严重,使用的时候注意下即可。

 

3)Public HashSet(int initialCapacity, float loadFactor)

    使用指定的参数,初始化内部map;具体见map的初始化方法。

 

4)Public HashSet(int initialCapacity)

    使用指定的参数,初始化内部map;具体见map的初始化方法。

 

5)Public HashSet(int initialCapacity, float loadFactor, Boolean dummy)

    使用指定的参数,初始化一个LinkedHashMap;

    这里的参数dummy,只是一个标识参数,没有具体的意义。

 

    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
	map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }

 

 

4.迭代器(Iterator)

    HashMap中为了方便地进行元素的遍历,提供了key的迭代器、value的迭代器、Entry的迭代器;在HashSet中,因为只有key有意义,所以仅通过HashMap的key的迭代器实现了整个HashSet的迭代器。如下:

 

    /**
     * Returns an iterator over the elements in this set.  The elements
     * are returned in no particular order.
     *
     * @return an Iterator over the elements in this set
     * @see ConcurrentModificationException
     */
    public Iterator<E> iterator() {
	return map.keySet().iterator();
    }

 

 

    见注释,迭代器中的元素的顺序不是特定的。

 

5.其他基本操作

    HashSet的基本操作,包括添加add、删除remove、元素包含检查contains、清除clear、判空isEmpty等等。

    其中add方法已经在初始化的时候介绍过了;

    其他的基本操作,也都是通过HashMap实现的;基本上,都是HashMap中原方法的直接调用。

 

    public boolean isEmpty() {
	return map.isEmpty();
    }

 

 

    这里实际上就是判断,map中的size是否为0;

 

    public boolean contains(Object o) {
	return map.containsKey(o);
    }

 

 

    使用参数o,到map中进行查询,查到表示包含;否则不包含。

 

    public boolean remove(Object o) {
	return map.remove(o)==PRESENT;
    }

 

 

    Remove和add是一对逆操作;HashMap的remove操作,返回的结果是旧的value。在这里,如果旧的结果是PRESENT,表示元素o,在HashSet中,此时返回true;否则,元素o不在HashSet中,返回false。经过这个方法之后,无论返回结果是false还是true;HashSet中都不包含元素o

    public void clear() {
	map.clear();
    }

 

    将map的元素情况,modCount清零;其他参数,loadFactor和数组长度等不变。

    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();
	}
    }

 

    返回结果的浅拷贝(shallow copy)

 

6.最后,为了序列化,HashSet也实现了序列化和反序列化方法readObject和writeObject

 

 

分享到:
评论

相关推荐

    HashSet工作原理_动力节点Java学院整理

    对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码:

    通过 HashMap、HashSet 的源代码分析其 Hash 存储机制1

    通过 HashMap、HashSet 的源代码分析其 Hash 存储机制1

    俄罗斯方块 JAVA 源代码

    JAVA版俄罗斯方块源代码 private boolean playing = false; private Shape shape; private ShapeFactory shapeFactory; private Ground ground; private GamePanel gamePanel; private JLabel lblMsg; ...

    Java中HashSet的解读

    HashSet源代码  HashSet 的实现  对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码: Java...

    java范例开发大全源代码

     实例204 利用HashSet删除学生 358  实例205 不重复的随机数序列 360  实例206 运用映射的相关类(Map) 363  实例207 运用集的相关类(Set) 365  12.2 List 368  实例208 增加所需的元素 368 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    2.2.7 Eclipse中的源代码编辑器 26 2.2.8 Eclipse的设置窗口 26 2.2.9 Eclipse中的其他视图 27 2.3 如何使用Eclipse 28 2.3.1 在Eclipse中创建自己的第一个项目 28 2.3.2 在Eclipse中编写HelloWorld程序 29 ...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    2.2.7 Eclipse中的源代码编辑器 26 2.2.8 Eclipse的设置窗口 26 2.2.9 Eclipse中的其他视图 27 2.3 如何使用Eclipse 28 2.3.1 在Eclipse中创建自己的第一个项目 28 2.3.2 在Eclipse中编写HelloWorld程序 29 ...

    java高手的文章合集3/3

    Java 推荐读物与源代码阅读.pdf JDBC-ODBC使用Excel作数据源.pdf JDBC中操作Blob、Clob等对象.pdf JDBC中驱动加载的过程分析(上).pdf JDBC中驱动加载的过程分析(下).pdf 从大学教育与工作的差距谈源代码阅读的...

    【应用C】C语言实现HashSet并模仿Java机制和语法(+源代码)-附件资源

    【应用C】C语言实现HashSet并模仿Java机制和语法(+源代码)-附件资源

    hashset去除重复值原理实例解析

    主要介绍了hashset去除重复值原理实例解析,具有一定借鉴价值,需要的朋友可以参考下。

    javajdk1.8源码-Java-source-reading:jdk1.8源代码分析

    缓慢更新一些个人学习java相关源码过程中的笔记,在这里你将不可避免地看到以下情况: 个别不懂/没想好的地方留空待补全 限于个人水平出现的解读错误 编辑错误 排版不统一 如发现有错,欢迎指正! 如果对你有用,...

    疯狂JAVA讲义

    1.5.1 编辑Java源代码 12 1.5.2 编译Java程序 13 学生提问:当我们使用编译C程序时,不仅需要指定存放目标文件的位置,也需要指定目标文件的文件名,这里使用javac编译Java程序时怎么不需要指定目标文件的文件名呢...

    java高手的文章合集 pdf格式

    Java 推荐读物与源代码阅读.pdf JDBC-ODBC使用Excel作数据源.pdf JDBC中操作Blob、Clob等对象.pdf JDBC中驱动加载的过程分析(上).pdf JDBC中驱动加载的过程分析(下).pdf JNI攻略之一――建立一个简单的JNI程序....

    Java集合框架源码剖析:HashSet 和 HashMap

     之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也是说HashSet里面有一个HashMap(适配器模式)。因此本文将重点分析HashMap。  HashMap实现了Map...

    class转成java源码-compilib:在运行时和内存中将Java源代码编译为Class对象

    一个小的实用程序库,用于在运行时将Java源代码编译为* .class对象。 主要针对编写单元测试: Set&lt; String &gt; sources = new HashSet&lt;&gt; (); sources . put( " package a.b; \n " + " public interface Consts {...

    Java范例开发大全 (源程序)

     实例204 利用HashSet删除学生 358  实例205 不重复的随机数序列 360  实例206 运用映射的相关类(Map) 363  实例207 运用集的相关类(Set) 365  12.2 List 368  实例208 增加所需的元素 368  实例...

    21天学通Java-由浅入深

    28 1.3 程序开发过程 29 1.4 编码规范 29 1.5 HelloWorld:第一个Java程序 30 1.5.1 编写程序代码 30 1.5.2 编译程序代码并运行 30 1.5.3 注意事项 31 1.6 使用Eclipse集成开发工具开发 32 1.7 综合练习 32 1.8 小结...

    java范例开发大全

    实例278 通过指定的URL可以获取网页的源代码 542 实例279 一对多通信模式 544 实例280 自制浏览器 549 实例281 扫描TCP端口 551 实例282 TCP协议服务器 552 实例283 TCP协议客户机 553 实例284 Socket连接信息 555 ...

Global site tag (gtag.js) - Google Analytics