集合(四): Map

 

更多實現類的源碼分析請點擊連接地址。。。。。。。java

一:    java.util.Map<k,v> 

public interface Map<K,V> { //....}

    Map用於保存具備映射關係的數據,所以Map集合(鍵值對的集合)裏保存着兩組值,一組值用於保存Map裏的key,另一組用於保存Map裏的value。數組

    Map中的 key 和 value 均可以是任何引用類型的數據。數據結構

    Map中的 Key 不容許重複,即同一個Map對象的任何兩個 Key 經過 equals 方法比較中返回  false。多線程

    key 和 value 之間存在單向一對一關係,即經過指定的key總能找到惟一的,肯定的value。併發

    將鍵映射到值的對象。一個映射不能包含重複的鍵;每一個鍵最多隻能映射到一個值。ide

    接下來將介紹Map中部分實現類:  源碼分析

                HashMap ,HashTable, TreeMap, LinkedHashMap , Properties 學習

二:    java.util.HashMap<k,v>

    HashMap是基於哈希表的Map接口的非同步實現。此實現提供全部可選的映射操做,並容許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變。this

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{
    ...

    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
    transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;

}

    HashMap其實是一個「鏈表散列」的數據結構,即數組和鏈表的結合體。源碼以下:spa

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;

         .....
}

更多內容源碼分析請學習:

         http://beyond99.blog.51cto.com/1469451/429789/

         http://alex09.iteye.com/blog/539545

接下來簡單瞭解下HashMaori中的基本方法:

首先定義一個Person:

public class Person implements Comparable<Person> {

	private String name;
	private int age;
	@Override
	public int compareTo(Person p) {
		if(p instanceof Person ){
			// return this.name.compareTo( p.name);  按升序排序
			return p.name.compareTo( this.name );
		}else{
			throw new ClassCastException("非Person類型。");
		}
	}
	/**
	 * 提供 構造方法,get set方法,hashCode 與 equals方法。
	 * */
}

而後在來看看HashMap的遍歷:

public class Test1HashMap {
	public static void main(String[] args) {
		
		Map<String,Person> map = new HashMap<String,Person>();
		
		Person p1 = new Person("Berg", 22);
		Person p2 = new Person("AA",21);
		Person p3 = new Person("BB",20);
		Person p4 = new Person("DD",23);
		Person p5 = new Person("EE",25);
		Person p6 = new Person("CC",19);
		
		//Map.put(String key, Person value)
		map.put("1", p1);
		map.put("2", p2);
		map.put("3", p3);
		map.put("4", p4);
		map.put("5", p5);
		map.put("6", p6);
		
		System.out.println(  map.size() );
		System.out.println(  map.containsKey( "6" ));
		System.out.println( map.containsValue( p2 ));
		
		System.out.println( "\n經過for循環Map.Entry遍歷Map:  ");
		// 接下來對map的遍歷:
		//1. for循環遍歷map
		for( Map.Entry<String, Person> entry : map.entrySet() ){
			System.out.println( entry.getKey() +" : "+ entry.getValue() );
		}
		
		System.out.println( "\n經過KeySet + Iterator 迭代遍歷Map:");
		// 2. 迭代
		Set<String> set = map.keySet();
		Iterator iterator = set.iterator();
		while( iterator.hasNext() ){
			String key = iterator.next().toString();
			Person p = map.get(key);
			System.out.println(  key + " : " + p );
		}
		
		// 3. 
		System.out.println( "\n經過entrySert方式遍歷Map ");
		Set<Entry<String, Person>> setentry = map.entrySet();
		Iterator<Entry<String, Person>>  iteratorSet = setentry.iterator();
		while( iteratorSet.hasNext() ){
			Entry<String, Person> entry = iteratorSet.next();
			System.out.println(  entry.getKey() + " : " + entry.getValue() );
		}
	}
}

 

更多HashMap源碼內容分析請學習:

                http://blog.csdn.net/chenssy/article/details/18323767

 

三:    java.util.HashTable<k,v>

    此類實現一個哈希表,該哈希表將鍵映射到相應的值。任何非 null 對象均可以用做鍵或值。

    爲了成功地在哈希表中存儲和獲取對象,用做鍵的對象必須實現 hashCode 方法和 equals 方法。

public class Hashtable<K,V> extends Dictionary<K,V>
                 implements Map<K,V>, Cloneable, java.io.Serializable {

    /**
     * The hash table data.
     */
    private transient Entry<K,V>[] table;
}

瞭解下HashMap與HashTable的區別:   

第一,繼承不一樣。

public class Hashtable<K,V>  extends Dictionary<K,V>
                                  implements Map<K,V>, Cloneable, java.io.Serializable
public class HashMap<K,V> extends AbstractMap<K,V>
                                     implements Map<K,V>, Cloneable, Serializable

第二

    Hashtable 中的方法是同步的,而HashMap中的方法在缺省狀況下是非同步的。在多線程併發的環境下,能夠直接使用Hashtable,可是要使用HashMap的話就要本身增長同步處理了。

第三

    Hashtable中,key和value都不容許出現null值。

    在HashMap中,null能夠做爲鍵,這樣的鍵只有一個;能夠有一個或多個鍵所對應的值爲null。當get()方法返回null值時,便可以表示 HashMap中沒有該鍵,也能夠表示該鍵所對應的值爲null。所以,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。

第四,兩個遍歷方式的內部實現上不一樣。

    Hashtable、HashMap都使用了 Iterator。而因爲歷史緣由,Hashtable還使用了Enumeration的方式 。

第五

    哈希值的使用不一樣,HashTable直接使用對象的hashCode。而HashMap從新計算hash值。

第六

    Hashtable和HashMap它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTable中hash數組默認大小是11,增長的方式是 old*2+1。HashMap中hash數組的默認大小是16,並且必定是2的指數。 

public class Test2HashTable {

	public static void main(String[] args) {
		
		Hashtable<String,String> ht = new Hashtable<String,String>();
		
		ht.put("1", "AAA");
		ht.put("2", "BBB");
		ht.put("3", "DDD");
		ht.put("4", "EEE");
		ht.put("5", "CCC");
		
		Enumeration<String> enumeration = ht.keys();
		while ( enumeration.hasMoreElements() ){
			System.out.print( enumeration.nextElement().toString() +"  " );
		}
		//遍歷
		for(Entry<String, String> entry: ht.entrySet() ){
			System.out.println( entry.getKey() + " : " + entry.getValue() );
		}
	}
}

    更多HashTable源碼內容分析請學習:

                    http://blog.csdn.net/chenssy/article/details/22896871

 

四:    java.util.LinkedHashMap

        Map 接口的哈希表和連接列表實現,具備可預知的迭代順序。此實現與 HashMap 的不一樣之處在於,後者維護着一個運行於全部條目的雙重連接列表。此連接列表定義了迭代順序,該迭代順序一般就是將鍵插入到映射中的順序(插入順序)。注意,若是在映射中從新插入 鍵,則插入順序不受影響。

    注意:LinkedHashMap繼承自HashMap,以下:

public class LinkedHashMap<K,V> extends HashMap<K,V>  implements Map<K,V>{}

注意: 

    HashMap使用哈希表來存儲數據,並用拉鍊法來處理衝突。

    LinkedHashMap繼承自HashMap,同時自身有一個鏈表,使用鏈表存儲數據,不存在衝突。

    LinkedList和LinkedHashMap同樣使用一個雙向循環鏈表,但存儲的是簡單的數據,並非「鍵值對」。

    因此HashMap和LinkedHashMap是Map,而LinkedList是一個List,這是他們本質的區別。

    LinkedList和LinkedHashMap均可以維護內容的順序,但HashMap不維護順序。

public class Test3LinkedHashMap {
	public static void main(String[] args) {
		
		LinkedHashMap<String, String> map = new LinkedHashMap<>();
		
		map.put("1", "AAA");
		map.put("2", "BBB");
		map.put("3", "DDD");
		map.put("4", "EEE");
		map.put("5", "CCC");
		
		// 遍歷
		for(Entry<String, String> entry: map.entrySet() ){
			System.out.println( entry.getKey() + " : " + entry.getValue() );
		}
	}
}

更多LinkedHashMap源碼內容分析請學習:

                http://blog.csdn.net/jzhf2012/article/details/8540688

 

五:    java.util.TreeMap<k,v>

        基於紅黑樹(Red-Black tree)的 NavigableMap實現。該映射根據其鍵的天然順序進行排序,或者根據建立映射時提供的 Comparator進行排序,具體取決於使用的構造方法。

public class TreeMap<K,V>  extends AbstractMap<K,V>
                      implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
    /**
     * The comparator used to maintain order in this tree map, or
     * null if it uses the natural ordering of its keys.
     *
     * @serial
     */
    private final Comparator<? super K> comparator;

    private transient Entry<K,V> root = null;

}

 注意:

    TreeMap 存儲Key-Value對時,須要根據Key對 key-value對進行排序。

    TreeMap 能夠保證全部的Key-Value的Key的排序。

    TreeMap 的Key的排序:

        -天然排序:TreeMap的全部的Key必須實現Comparable接口,並且全部的key應該是同一個類的對象,不然會拋出ClassCastException。

        -定製排序:建立TreeMap時,傳入一個Comparator對象,該對象負責對TreeMap中的全部的key進行排序,此時不須要Map的key實現Comparable接口。

首先先看看Person 與 Person2的不一樣:

前者實現了Comparable 然後者沒有,以下:

Person:

public class Person implements Comparable<Person> {

	private String name;
	private int age;
	
	@Override
	public int compareTo(Person p) {
		if(p instanceof Person ){
			// return this.name.compareTo( p.name);  按升序排序
			return p.name.compareTo( this.name );
		}else{
			throw new ClassCastException("非Person類型。");
		}
	}
	
	/**
	 * 提供 構造方法,get set方法,hashCode 與 equals方法。
	 * */
}

Person2:

public class Person2{
	private String name;
	private int age;
}

而後比較兩種不一樣方式的排序:

public class Test4TreeMap {
	public static void main(String[] args) {

		// Person實現Comparable ,
		TreeMap<Person,String> map = new TreeMap<Person,String>();

		Person p1 = new Person("Berg", 22);
		Person p2 = new Person("AA",21);
		Person p3 = new Person("BB",20);
		Person p4 = new Person("DD",23);
		Person p5 = new Person("EE",25);

		// 能夠嘗試將下面的  K V 對換如下,  
		//可是當用 Person對象當作 key的時候,Person必須實現Comparable 
		map.put(p1, "AAA");
		map.put(p2, "BBB");
		map.put(p3, "DDD");
		map.put(p4, "EEE");
		map.put(p5, "CCC");

		// 遍歷 , 默認按照鍵的天然順序排序 且升序排序
		for(Entry<Person, String> entry: map.entrySet() ){
			System.out.println( entry.getKey() + " : " + entry.getValue() );
		}

		
		
		System.out.println( "\n\n定製排序**********************");
		//**********************************************
		// 不須要Person2對象實現Comparable接口。

		//根據建立映射時提供的 Comparator進行排序
		Comparator<Object> comparator = new Comparator<Object>() {
			@Override
			public int compare(Object o1, Object o2) {
				if( o1 instanceof Person2  && o2 instanceof Person2){
					Person2 p1 = (Person2) o1;
					Person2 p2 = (Person2) o2;
					return p2.getAge() - p1.getAge();
				}else{
					throw new ClassCastException("非Person2類型。");
				}
			}
		};

		TreeMap<Person2,String> map1 = new TreeMap<Person2,String>(comparator);
		Person2 p21 =  new Person2("AA", 19);
		Person2 p22 =  new Person2("BB", 20);
		Person2 p23 =  new Person2("CC", 21);
		Person2 p24 =  new Person2("EE", 23);
		Person2 p25 =  new Person2("DD", 24);
		Person2 p26 =  new Person2("AA", 19);

		map1.put(p21, "AAA");
		map1.put(p22, "BBB");
		map1.put(p23, "DDD");
		map1.put(p24, "EEE");
		map1.put(p25, "CCC");
		map1.put(p26, "AAA");

		// 遍歷 , 默認按照鍵的天然順序排序 且升序排序
		for(Entry<Person2, String> entry: map1.entrySet() ){
			System.out.println( entry.getKey() + " : " + entry.getValue() );
		}
	}
}

 

更多TreeMap源碼內容分析請學習:

                http://blog.csdn.net/chenssy/article/details/26668941

 

六:    java.util.Peroperties

     Properties 類是 HashTable的子類,該對象用於處理屬性文件。

    因爲屬性文件裏的key value都是字符串類型, 因此properties裏的key 和 value 都是字符串類型的。

public class Properties extends Hashtable<Object,Object> { ...}

先看看一個db.properties中文件內容:

username=xujun
password=berg
blogaddress=http://my.oschina.net/gently/blog

而後讀取這個屬性文件:

public class Test5Properties {

	public static void main(String[] args) throws IOException {

		//以流的方式讀取屬性文件。
		// 文件是從SRC根目錄下開始掃描。
		InputStream iis= Test5Properties.class.getClassLoader().getResourceAsStream( "db.properties" );
		//建立對象
		Properties p = new Properties();
		//經過load將流中的數據讀取到P中,造成鍵值。
		p.load( iis );  // inputstream
		//p.load( iis );  reader 

		for( Map.Entry entry : p.entrySet() ){
			System.out.println(  entry.getKey() +"\t"+ entry.getValue()  );
		}

		iis.close();
	}

}

輸出:

blogaddress	http://my.oschina.net/gently/blog;
password	berg;
username	xujun;
相關文章
相關標籤/搜索