HashMap学习小结

来源:互联网 发布:农历转换公历js 编辑:程序博客网 时间:2024/06/06 01:04
一、HashMapTreeMap
        在数组中,通过数组下标来对其内容索引;在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做valueHashMap实现Map接口,提供所有映射操作的实现,并且允许null的键和值。HashMap中插入和查询key/value的开销是一个固定常量。HashMap不保证映射后的其内容的顺序在一定的时间内不会变化,也就是说,HashMap中元素的排列顺序是无序的(TreeMap是有序的)如例1
1
import java.util.*;
class HashMaps
{
  
public static void main(String[] args)
  {
    HashMap map 
= new HashMap();
    map.put(
"1""111");
    map.put(
"4""444");
    map.put(
"2""222");
    map.put(
"5""555");
   
    Iterator it 
= map.keySet().iterator();
    
while (it.hasNext())
    {
      Object mapKey 
= it.next();
      System.out.println(
"map.get(key) is : " + map.get(mapKey));
    }
   
    TreeMap tree 
= new TreeMap();
    tree.put(
"1""111");
    tree.put(
"4""444");
    tree.put(
"2""222");
    tree.put(
"5""555");
    Iterator it_2 
= tree.keySet().iterator();
    
while(it_2.hasNext())
    {
      Object treeKey 
= it_2.next();
      System.out.println(
"tree.get(key) is : " + tree.get(treeKey));
    }
  }
}
        运行结果:
map.get(key) is : 222
map.get(key) is : 111
map.get(key) is : 555
map.get(key) is : 444
tree.get(key) is : 111
tree.get(key) is : 222
tree.get(key) is : 444
tree.get(key) is : 555       
        因为HashMap通过hashCode对进行查找,所以HashMap中元素的排列顺序是不固定的TreeMap在查看key/value的时候,元素会被排序,其次序由ComparableComparator决定,因此查询得到的结果是有序地。如果你需要得到一个有序的结果你就应该使用TreeMap
二、HashMap的使用
        HashMap通过get()/put()方法来查询和插入,还有一个很有用的方法ContainsKey()check对象是否存在于HashMap中。如例2
2
import java.util.*;
public class HashMaps
{
  
public static void main(String[] args)
  {
    HashMap aMap 
= new HashMap();
    Random ran 
= new Random();
   
    
for (int i = 0; i<100; i++)
    {
      Integer iVal 
= new Integer(ran.nextInt(10));
      
if (aMap.containsKey(iVal))
      {
        ((CCount)aMap.get(iVal)).count
++;
      }
      
else
      {
        aMap.put(iVal, 
new CCount());
      }
    }
    System.out.println(aMap);
  }
}
 
class CCount
{
  
int count = 1;
  
public String toString()
  {
    
return Integer.toString(count);
  }
}
        2中生成1000-9的任意整数,并统计了每个数出现的次数,然后以0-9的数为key,将他们出现的次数(count)作为value保存到HashMap中。
        HashMap是基于HashCode的,在所有对象的超类Object中有一个HashCode()方法。当使用标准库中的类Integer作为HashMapkey时,程序能够正常运行,但是如果使用自定义的类作为HashMapkey时,可能会出现错误。这是因为HashMap通过key查找value时,实际上是计算key对象地址的散列码来确定value的。默认情况下,我们使用超类Object的方法HashCode()来生成散列码。这样,假如我们用同样的初始化参数构造同样内容的对象,由于他们的地址不同,生成的散列码也不同。如下例所示:
3
import java.util.*;
public class HashMaps
{
  
public static void main(String[] args)
  {
    HashMap aMap 
= new HashMap();
    
for (int i = 0; i<10; i++)
      aMap.put(
new Element(i), new Figureout());
    System.out.println(
"aMap: get result:");
    Element test 
= new Element(5);
    
if (aMap.containsKey(test))
      System.out.println((Figureout)aMap.get(test));
    
else
      System.out.println(
"Not found");
  }
}
 
class Element
{
  
int num;
  
public Element(int n)
  {
    num 
= n;
  }
}
 
class Figureout
{
  Random r 
= new Random();
  
boolean possible = r.nextDouble() > 0.5;
  
public String toString()
  {
    
if (possible)
      
return "OK";
    
else
      
return "Impossible";
  }
}

        3中,先是在for循环中通过new Element(i)生成了一个HashMap,之后,我们希望查找一个test元素,这个test元素是通过new Element(5)生成的。test元素和HashMap中的元素是不同的对象,因此,它们的地址也不同,使用默认的Object超类提供的HashCode方法无法查找。所以,例3中程序执行结果始终是“Not found”。
        因此,对于用户自定义的类作key的情况,我们需要覆盖HashCode方法。同时,还需要覆盖equals方法来判断当前的key是否与HashMap中的元素的key相同。修改后的Element类如下:
class Element
{
  
int num;
  
public Element(int n)
  {
    num 
= n;
  }
  
public int hashCode()
  {
      
return num;
  }
  
public boolean equals(Object o)
  {
      
return (o instanceof Element) && (num==((Element)o).num);
  }
}
        这里Element覆盖了Object中的hashCode()equals()方法。覆盖hashCode()使其以number的值作为 hashCode返回,这样对于相同内容的对象来说它们的hashCode也就相同了。
三、小结
1,如果要用自己的类作为HashMapkey,必须同时覆盖hashCodeequals方法。
2,重写hashCode方法的关键:
(1)对同一个对象调用hashCode()都应该生成同样的值。
(2)hashCode()方法不要依赖于对象中易变的数据,当数据发生变化时,hashCode()就会生成一个不同的散列码,即产生了一个不同的label
(3)hashCode()不应依赖于具有唯一性的对象信息,例如对象地址。
(4)散列码应该更关心速度,而不是唯一性,因为散列码不必是唯一的。
(5)好的hashCode()应该产生分步均匀的散列码。
3,正确的equals()方法满足五个条件:
(1)自反性。对于任意的xx.equals(x)一定返回true
(2)对称性。对于任意的xy,如果y.equals(x)返回true,则x.equals(y)也返回true
(3)传递性。对于任意的xyz,如果有x.equals(y)返回truey.equals(z)返回true,则x.equals(z)一定返回true
(4)一致性。对于任意的xy,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false
(5)对任何不是nullxx.equals(null)一定返回false