import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* HashMap:
* 基於哈希表的 Map 接口的實現。此實現提供所有可選的映射操作,並允許使用 null 值和 null 鍵。
* (除了非同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恆久不變
*
* 注意
* 此實現不是同步的。如果多個線程同時訪問一個哈希映射,而其中至少一個線程從結構上修改了該映射,則它必須 保持外部同步。
* (結構上的修改是指添加或刪除一個或多個映射關係的任何操作;僅改變與實例已經包含的鍵關聯的值不是結構上的修改。)
* 這一般通過對自然封裝該映射的對象進行同步操作來完成。如果不存在這樣的對象,則應該使用 Collections.synchronizedMap 方法來“包裝”該映射。
* 最好在創建時完成這一操作,以防止對映射進行意外的非同步訪問,如下所示:
* Map m = Collections.synchronizedMap(new HashMap(...));
* 由所有此類的“collection 視圖方法”所返回的迭代器都是快速失敗 的:在迭代器創建之後,如果從結構上對映射進行修改,除非通過迭代器本身的 remove 方法,
* 其他任何時間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。因此,面對併發的修改,迭代器很快就會完全失敗
* 而不冒在將來不確定的時間發生任意不確定行爲的風險。
*
*
* 底層採用哈希表作爲數據結構
* HashMap默認分組:16,必須是2的N次方數
* //The default initial capacity - MUST be a power of two.
* static final int DEFAULT_INITIAL_CAPACITY = 16
*
* HashMap擴容機制: 分組組數*2
* HashMap的主鍵和值都可以爲null
* HashMap是多線程的
* hashCode&(分組組數-1)
* -------------------------------------
* HashMap的基本用法:
* 1.創建HashMap -> new HashMap<K,V>();
* 2.添加元素 -> put(K,V);
* 在HashSet當中,添加元素被認爲是相同元素時,新元素捨棄,老元素不變
* 在HashMap當中,由於HashSet就是HashMap的主鍵部分,所以HashMap的主鍵相同,在主鍵被認定爲相同元素的時候,主鍵不變 而值進行覆蓋
* 3.獲得元素個數 -> map.size();
* 4.判斷是否包含主鍵 -> containsKey(K); boolean
* 5.判斷是否包含值 -> containsValue(V); boolean
* 6.刪除元素 -> remove(K)
* 7.遍歷
* 1.根據主鍵: Set<String> set = hm.keySet(); key
* 2.根據值 : Collection<Integer> set = hm.value(); value
* 3.Set<Map.Entry<String, Integer>> set3 = hm.entrySet(); key=value
* 4.Iterator<String> car = hm.keySet().iterator();
*
* ==============================================================================================================
* Hashtable
* 此類實現一個哈希表,該哈希表將鍵映射到相應的值。任何非 null 對象都可以用作鍵或值。
* 爲了成功地在哈希表中存儲和獲取對象,用作鍵的對象必須實現 hashCode 方法和 equals 方法。
* Hashtable 的實例有兩個參數影響其性能:初始容量 和加載因子。容量 是哈希表中桶 的數量,初始容量 就是哈希表創建時的容量。
* 注意
* 哈希表的狀態爲 open:在發生“哈希衝突”的情況下,單個桶會存儲多個條目,這些條目必須按順序搜索。加載因子 是對哈希表在其容量自動增加之前可以達到多滿的一個尺度。
* 初始容量和加載因子這兩個參數只是對該實現的提示。關於何時以及是否調用 rehash 方法的具體細節則依賴於該實現。
*
* 下面這個示例創建了一個數字的哈希表。它將數字的名稱用作鍵:
*
* Hashtable<String, Integer> numbers
* = new Hashtable<String, Integer>();
* numbers.put("one", 1);
* numbers.put("two", 2);
* numbers.put("three", 3);
* 要獲取一個數字,可以使用以下代碼:
*
* Integer n = numbers.get("two");
* if (n != null) {
* System.out.println("two = " + n);
* }
* }
* 注意
* 迭代器的快速失敗行爲無法得到保證,因爲一般來說,不可能對是否出現不同步併發修改做出任何硬性保證。
* 快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException。
* 因此,爲提高這類迭代器的正確性而編寫一個依賴於此異常的程序是錯誤做法:迭代器的快速失敗行爲應該僅用於檢測程序錯誤。
*
* Hashtable 線程是同步的 是synchronized修飾的
*-------------------------------------------------------------------------------------------------
*Hashtable 的基本用法跟HashMap基本一致,不同點在於 HashTable是同步的,而HashMap是非同步的
* Hashtable 底層採用哈希表作爲數據結構
* Hashtable 默認分組16,分組組數是任意的
* Hashtable 擴容機制 分組組數*2+1
* Hashtable 主鍵和值都不允許爲null
* Hashtable 線程是安全的
* hashCode%分組組數
*==================================================================================================
*ArrayList 和 Vector 的區別:
* ArrayList和Vector底層都是採用數組作爲數據結構
* Vector 是同步的,ArrayList是非同步的
* ArrayList底層默認分配10塊空間,擴容機制:*3/2+1 1.5倍擴容
* public void ensureCapacity(int minCapacity) {
* modCount++;
* int oldCapacity = elementData.length;
* if (minCapacity > oldCapacity) {
* Object oldData[] = elementData;
* int newCapacity = (oldCapacity * 3)/2 + 1;
* if (newCapacity < minCapacity)
* newCapacity = minCapacity;
* // minCapacity is usually close to size, so this is a win:
* elementData = Arrays.copyOf(elementData, newCapacity);
* }
* }
* Vector 底層雖然也是默認11塊空間.但擴容機制是*2
* private void ensureCapacityHelper(int minCapacity) {
* int oldCapacity = elementData.length;
* if (minCapacity > oldCapacity) {
* Object[] oldData = elementData;
* int newCapacity = (capacityIncrement > 0) ?
* (oldCapacity + capacityIncrement) : (oldCapacity * 2);
* if (newCapacity < minCapacity) {
* newCapacity = minCapacity;
* }
* elementData = Arrays.copyOf(elementData, newCapacity);
* }
* }
*HashMap 和 Hashtable 的區別:
* HashMap 是多線程的(非同步),Hashtable 是單線程的(同步的)
* HashMap 底層默認16組,擴容機制是分組組數*2
* HashMap 允許主鍵和值都爲空,當添加主鍵相同的元素時,逐主鍵不變,值進覆蓋
* Hashtable 主鍵和值都不可以爲空 "" 和 null 是不一樣的 ""可以存放,null或導致Hashtable 拋出空指針異常
* Hashtable 默認11組,擴容機制是*2+1
*
* */
public class TestHashMap2{
public static void main(String[] args){
HashMap_Basic_Usage hbu = new HashMap_Basic_Usage();
//hbu.create();
TestHashtable ht = new TestHashtable();
ht.show();
}
}
//HashMap的基本用法
class HashMap_Basic_Usage{
public void create(){
//創建HashMap
HashMap<String,Integer> hm = new HashMap<String,Integer>();
//添加基本數據類型元素
hm.put("tom", 18);
hm.put("jreey", 19);
//測試添加空值
hm.put(null,null);//當兩個主鍵相同的時候,主鍵不變 值進行覆蓋 後來的覆蓋原有的
hm.put(null, 100);//
hm.put("etoak", 500);
//獲得hm元素映射數量
//System.out.println(hm.size());
//根據主鍵獲得對應的值
//System.out.println(hm.get("tom"));
//isEmpty判斷集合是否爲空
//System.out.println(hm.isEmpty());
//containsKey 集合中是否包含主鍵 返回boolean 類型
//System.out.println(hm.containsKey("jreey"));
//containsValue 集合中是否包含值 - boolean
//System.out.println(hm.containsValue(21));
//根據主鍵 刪除元素
//hm.remove("tom");
//遍歷
//1. 使用Set接口 根據主鍵進行遍歷
Set<String> set = hm.keySet();
for(String str:set){
//System.out.println(str);
//System.out.println("Key is:"+str+" Value is:"+hm.get(str));
}
//2. 使用Collection接口 根據值進行遍歷
Collection<Integer> set2 = hm.values();
for(Integer in:set2){
//System.out.println(in);
}
//3.
Set<Map.Entry<String, Integer>> set3 = hm.entrySet();
for(Map.Entry me:set3){
//System.out.println(me);
//System.out.println("Key is:"+me.getKey()+" Value is:"+me.getValue());
}
//Iterator
Iterator<String> car = hm.keySet().iterator();
while(car.hasNext()){
String str = car.next();//返回的是Object類型 要麼強轉爲String類型或是.toString()或是+"",再或是在創建迭代器的時候 直接指定迭代的要迭代的類型
System.out.println(str+"="+hm.get(str));
}
}
}
//Hashtable
class TestHashtable{
public void show(){
Hashtable<Integer,String> ht = new Hashtable<Integer,String>();
ht.put(1, "");
ht.put(2, "2");
ht.put(1, "1");
//ht.put(null, "3");
//ht.put(4, null);
Set<Map.Entry<Integer, String>> set = ht.entrySet();
for(Map.Entry me:set)
System.out.println(me);
}
}
HashMap 補充:
import java.util.*;
public class TestHashMap2{
public static void main(String[] args){
HashMap<Student,String> hm = new HashMap<Student,String>();
/**
在HashSet當中,當添加的元素被認爲是相同的對象的時候
新元素捨棄老元素不變!
在HashMap當中,由於HashSet就是HashMap的主鍵部分
所以HashMap的主鍵同樣,在添加主鍵被認爲是相等的元素
的時候,主鍵不變,而值進行覆蓋
*/
Student s1 = new Student("小白",20);
Student s2 = new Student("小黑",20);
hm.put(s1,s1.name);
hm.put(s2,s2.name);
System.out.println(hm);
}
}
class Student{
String name;
int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name + " " + age;
}
public boolean equals(Object obj){
if(obj == null) return false;
if(!(obj instanceof Student)) return false;
if(obj == this) return true;
Student s1 = (Student)obj;
return s1.age == this.age;
}
public int hashCode(){
return age;
}
}