HashMap学习小结

一、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

你可能感兴趣的:(Java学习)