黑马程序员技术交流社区

标题: HashSet的底层实现是这样的,这样理解对不对? [打印本页]

作者: 赵宇    时间: 2012-9-22 09:51
标题: HashSet的底层实现是这样的,这样理解对不对?
本帖最后由 赵宇 于 2012-9-25 08:37 编辑

public HashSet() {
map = new HashMap<E,Object>();
    }
Hashset 的低层是使用 HashMap实现的。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
    }
当使用add 方法添加对象到set当中时实际上是将对象作为低层所维护的Map对象的Key,而value,则是一个Object对象,用不到。



那HashMap 的实现我就不太理解了 谁能讲讲 thank u


作者: 程振    时间: 2012-9-22 09:54
恩,体现出了代码的重用
作者: 张 涛    时间: 2012-9-22 10:03
hashSet源码,楼主的想法是对的:
  1. public class HashSet<E>
  2.     extends AbstractSet<E>
  3.     implements Set<E>, Cloneable, java.io.Serializable
  4. {
  5.     static final long serialVersionUID = -5024744406713321676L;

  6.     private transient HashMap<E,Object> map;

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

  9. /**
  10.      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  11.      * default initial capacity (16) and load factor (0.75).
  12.      */
  13.     public HashSet() {
  14.         map = new HashMap<E,Object>();
  15.     }

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

  29.     /**
  30.      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  31.      * the specified initial capacity and the specified load factor.
  32.      *
  33.      * @param      initialCapacity   the initial capacity of the hash map
  34.      * @param      loadFactor        the load factor of the hash map
  35.      * @throws     IllegalArgumentException if the initial capacity is less
  36.      *             than zero, or if the load factor is nonpositive
  37.      */
  38.     public HashSet(int initialCapacity, float loadFactor) {
  39.         map = new HashMap<E,Object>(initialCapacity, loadFactor);
  40.     }

  41.     /**
  42.      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  43.      * the specified initial capacity and default load factor (0.75).
  44.      *
  45.      * @param      initialCapacity   the initial capacity of the hash table
  46.      * @throws     IllegalArgumentException if the initial capacity is less
  47.      *             than zero
  48.      */
  49.     public HashSet(int initialCapacity) {
  50.         map = new HashMap<E,Object>(initialCapacity);
  51.     }

  52.     /**
  53.      * Constructs a new, empty linked hash set.  (This package private
  54.      * constructor is only used by LinkedHashSet.) The backing
  55.      * HashMap instance is a LinkedHashMap with the specified initial
  56.      * capacity and the specified load factor.
  57.      *
  58.      * @param      initialCapacity   the initial capacity of the hash map
  59.      * @param      loadFactor        the load factor of the hash map
  60.      * @param      dummy             ignored (distinguishes this
  61.      *             constructor from other int, float constructor.)
  62.      * @throws     IllegalArgumentException if the initial capacity is less
  63.      *             than zero, or if the load factor is nonpositive
  64.      */
  65.     HashSet(int initialCapacity, float loadFactor, boolean dummy) {
  66.         map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
  67.     }
复制代码

作者: 程金    时间: 2012-9-22 10:13
本帖最后由 程金 于 2012-9-22 10:15 编辑

昨天才学的集合,楼主理解的没错.
HashSet是基于HashMap实现的,可以看做特殊的hashMaP
hashSet里面有一个HashMap;
HashSet中的元素都存放在这个HashMap的key上面,
而这个Hashmap的value中的值都是统一的一个Object常量:private static final Object PRESENT = new Object()。
HashSet跟HashMap一样,都是一个存放链表的数组。
HashSet中add方法调用的是底层HashMap中的put()方法,而如果是在HashMap中调用put,首先会判断key是否存在,如果key存在则修改value值,如果key不存在这插入这个key-value。而在set中,因为value值没有用,也就不存在修改value值的说法,因此往HashSet中添加元素,首先判断元素(也就是key)是否存在,如果不存在这插入,如果存在着不插入,这样HashSet中就不存在重复值。
HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成

作者: 张忠豹    时间: 2012-9-22 13:17
1.    HashMap概述:
   HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

2.    HashMap的数据结构:
    HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。首先,HashMap类的属性中定义了Entry类型的数组。Entry类实现java.ultil.Map.Entry接口,同时每一对key和value是作为Entry类的属性被包装在Entry的类中。


HashMap的部分源码如下:

Java代码  
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/  
  
transient Entry[] table;  
   
static class Entry<K,V> implements Map.Entry<K,V> {  
    final K key;  
    V value;  
    Entry<K,V> next;  
    final int hash;  
    ……  
}  

    可以看出,HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。table数组的元素是Entry类型的。每个 Entry元素其实就是一个key-value对,并且它持有一个指向下一个 Entry元素的引用,这就说明table数组的每个Entry元素同时也作为某个Entry链表的首节点,指向了该链表的下一个Entry元素,这就是所谓的“链表散列”数据结构,即数组和链表的结合体。

归纳起来简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2