疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

HashSet与HashMap、Hashtable


 

HashMap

 
        HashMap是一个有序的集合,是有一对属性值的集合,属性包含key,和value。关键字key是唯一不重复的,查询起来速度很快。
 
        HashMap 的实例有两个参数影响其性能:初始容量 和 加载因子。容量是 哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,通过调用 rehash 方法将容量翻倍。  
        通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地降低 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
 
        HashSet
 
         而HashSet(散列表)就像是把HashMap中value去掉,说白了就是只有一个key的HashMap集合。它实现了Set接口,意味着它的元素不能有重复值出现。HashSet中有add、remove、contains 和 size方法,没有get()方法,但可以通过iterator()来实现,迭代所需的时间与 HashSet 实例的大小(元素的数量)成比例。且对于 HashSet 而言,它是基于 HashMap 实现的。
 
 
        下面是HashSet的源代码:
 
 
 
 
public class HashSet<E> extends AbstractSet<E> 
     implements Set<E>, Cloneable, java.io.Serializable 
 { 
     // 使用 HashMap 的 key 保存 HashSet 中所有元素
     private transient HashMap<E,Object> map; 
     // 定义一个虚拟的 Object 对象作为 HashMap 的 value 
     private static final Object PRESENT = new Object(); 
     ... 
     // 初始化 HashSet,底层会初始化一个 HashMap 
     public HashSet() 
     { 
         map = new HashMap<E,Object>(); 
     } 
     // 以指定的 initialCapacity、loadFactor 创建 HashSet 
     // 其实就是以相应的参数创建 HashMap 
     public HashSet(int initialCapacity, float loadFactor) 
     { 
         map = new HashMap<E,Object>(initialCapacity, loadFactor); 
     } 
     public HashSet(int initialCapacity) 
     { 
         map = new HashMap<E,Object>(initialCapacity); 
     } 
     HashSet(int initialCapacity, float loadFactor, boolean dummy) 
     { 
         map = new LinkedHashMap<E,Object>(initialCapacity 
             , loadFactor); 
     } 
     // 调用 map 的 keySet 来返回所有的 key 
     public Iterator<E> iterator() 
     { 
         return map.keySet().iterator(); 
     } 
     // 调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 Set 里元素的个数
     public int size() 
     { 
         return map.size(); 
     } 
     // 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空,
     // 当 HashMap 为空时,对应的 HashSet 也为空
     public boolean isEmpty() 
     { 
         return map.isEmpty(); 
     } 
     // 调用 HashMap 的 containsKey 判断是否包含指定 key 
     //HashSet 的所有元素就是通过 HashMap 的 key 来保存的
     public boolean contains(Object o) 
     { 
         return map.containsKey(o); 
     } 
     // 将指定元素放入 HashSet 中,也就是将该元素作为 key 放入 HashMap 
     public boolean add(E e) 
     { 
         return map.put(e, PRESENT) == null; 
     } 
     // 调用 HashMap 的 remove 方法删除指定 Entry,也就删除了 HashSet 中对应的元素
     public boolean remove(Object o) 
     { 
         return map.remove(o)==PRESENT; 
     } 
     // 调用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素
     public void clear() 
     { 
         map.clear(); 
     } 
     ... 
 }
 
 
 
Hashtable
 
 
        另外还有Hashtable ,网上说这三个的区别在面试时经常会遇到,呵呵,但到现在好像很少遇到Hashtable,是因为HashMap是新框架中用来代替HashTable的类么?Hashtable是Dictionary的子类,方法是同步的,不允许null值(key和value都不可以),而HashMa是Map接口的一个实现类,方法是异步的,允许null值出现。
 
 
       一些简单的测试程序,摘下了,便于理解:
 
 
public static void main(String[] args) {
  Hashtable<Integer, String> table = new Hashtable<Integer, String>();
  table.put(1, "1");
  //table.put(2, null);   //Hashtable 不允许null值 有null就会报异常
  
for(int i=0;i<table.size();i++){
   System.out.println(table.get(1));
  }
  System.out.println("#############");
  HashMap<Integer, String> map = new HashMap<Integer, String>();
  map.put(1, "2");
  map.put(2, "3");
  map.put(null,null);      //HashMap 允许null值,但key只能有一个null,否则后面不会被保存,
  for(int i=0;i<map.size();i++){
   System.out.println(map.get(1));
  }
  
  System.out.println("#############");
//HashSet  值不能重复  无序的不能用get()来取对象
  HashSet<Integer> s = new HashSet<Integer>();
  s.add(Integer.valueOf(1));
  s.add(Integer.valueOf(1));
  for(Integer i:s){
   System.out.println(i);
  }
 }