Java Collections Framework--(三 Map)

来源:互联网 发布:法语自学软件app 编辑:程序博客网 时间:2024/05/01 03:05
 

7.WeakHashMap VS HashMap VS Hashtable

WeakHashMapHashMap实现大体一致,但WeakHashMapkey实行弱引用,如果一个key不再被外部所引用,那么该key可以被GC回收。HashMapHashtable实现大体一致,但Hashtable支持线程同步,HashMap不支持。需要同步操作的理由是,可能存在多个线程对同一个集合进行操作的情况:譬如一个线程正在对某集合进行遍历,但与此同时,另一个线程又在对该集合进行插入或删除,那么第一个线程的遍历结果将是不可预测的,对于同步集合,它将会抛出一个ConcurrentModificationException异常,JCF把这种机制成为“fail-fast”

8.使用HashMap WeakHashMap需要注意的问题

 

public class Testk {

int i = 1;

public Testk(int i) {

this.i = i;

}

public int getI() {

return i;

}

public boolean equals(Object test){

if((test instanceof Testk) && i == ((Testk)test).i){

return true;

}else return false;

}

}

 

 

 

 

 

import java.util.Collection;

import java.util.Iterator;

import java.util.Set;

import java.util.HashMap;

import java.util.Map.Entry;

 

public class MapTry {

   

    HashMap<Testk, Integer> weak = new HashMap<Testk, Integer>();

    Testk test1 = new Testk(1);

    Testk test2 = new Testk(2);

    Testk test3 = new Testk(3);

    Testk test4 = new Testk(4);

    Testk test5 = new Testk(5);

    Testk test6 = new Testk(6);

    public MapTry() {

        weak.put(test1,1);

        weak.put(test2,2);

        weak.put(test3,3);

        weak.put(test4,4);

        weak.put(test5,5);

        weak.put(test6,6);

    }

    public static void main(String[] args){

       

        MapTry k = new MapTry();

        Testk test7 = new Testk(5);

        System.out.println(k.weak.get(test7));

    }

}

输出的结果是null,为什么输出不是5

test7.equals(test5)==true,怎么k.weak.get(test7)会得到null呢?

原因是HashMap存储,查找,删除对象时,先算出对象的HashCode值,在经过一个“一定”的算法,得到一个整形值h,再将对象存于数组元素Entry<K,V> table[h]中。

static int hash(Object x) {

        int h = x.hashCode();      //h是x的HashCode

        h += ~(h << 9);

        h ^=  (h >>> 14);

        h +=  (h << 4);

        h ^=  (h >>> 10);

        return h;

    }

 

而HashMap的HashCode方法继承自Object,HashCode方法返回的HashCode对应于当前的地址,对于不同的对象,即使它们的内容完全相同,用HashCode()返回的值也不同。

这就要求我们覆盖HashCode方法(有很多书介绍如何写出合理的HashCode方法)。把Testk改成:

public class Testk {

int i = 1;

public Testk(int i) {

this.i = i;

}

public int getI() {

return i;

}

public boolean equals(Object test){

if((test instanceof Testk) && i == ((Testk)test).i){

return true;

}else return false;

}

public int hashCode(){

        return i;

}

}

另外还要注意的一点是,上面的equals方法不能写成:

public boolean equals(Testk test){

if(i == test.i){

return true;

}else return false;

}

这是因为java.util.HashMap中对比两个对象是否相等用的是equals(Object o)方法。

9.TreeMap VS HashMap

TreeMap按照树形组织元素,但是以Iterator输出时是按照固定顺序的,这种顺序按照key的比较,从小到大。HashMap没有固定的顺序,但是不管从添加,查询,删除的执行效率都要比TreeMap高。

10.IdentityHashMap VS HashMap

 

IdentityHashMap对键成员采用的是严格相等比较,下面是IdentityHashMap的取值方法:

public V get(Object key) {

        Object k = maskNull(key);

        Object[] tab = table;

        int len = tab.length;

        int i = hash(k, len);

        while (true) {

        Object item = tab[i];

            if (item == k)          //对比Key

                return (V) tab[i + 1];

            if (item == null)

                return null;

            i = nextKeyIndex(i, len);

        }

 }

对比Key是否相等用的是item == k,而不是item == k || item.equals(k),所以两个键对象是同一内存对象时才相等,即由同一个new操作产生才相等。还有一点就是HashMap的存储结构与IdentityHashMap的存储结构不一样,HashMap的Entry<K,V> table[]的数组元素都相当于一个桶,HashCode相同的实体(Entry<K,V>)存在同一个table[i]下,如table[2]下可能存储几个Entry<K,V>,每个Entry<K,V>中有一个私有变量(Entry<K,V> next),该变量指向下一个Entry<K,V>,这样几个Entry<K,V>就以链式结构存储于table[2]中。但IdentityHashMap中如果HashCode值相同,就会通过一个固定的算法重复运算,直到得到的HashCode值对应的table[i]中未被存储过,才将其存进去。

11.HashMap VS LinkedHashMap

HashMap与LinkedHashMap存储结构一样,不过用Iterator遍历HashMap时得到的元素是没有先后顺序的,而LinkedHashMap把加入的元素按加入先后顺序连起来,用Iterator遍历时按加入的先后得到各个元素。需要注意的一点是:

 LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)

如果accessOrdertrue时,用get(Object key)得到元素后,该实体会从链中取出,然后连接到链的链尾,默认accessOrderfalse

12.EnumMap

枚举类型定义一个固定的、封闭的值集合,然后,在需要这些值中的某一个值时,可以通过它的名称来指定它,这就是枚举类型的简单性.枚举类型的值就是枚举类型的实例,编译器会确保没有传入其他的类型,这就是枚举类型的安全性.但我感觉EnumMap用的比较少,可以用其它集合结构取代。当然,既然它存在于java.util.*中,就必然有其优势。

 

原创粉丝点击