一、hashmap底層原理:
hashmap調用默認構造方法會產生一個默認底層是長度為16的Entry數組,首先調用key的hasCode()方法來得到一個整數, int hash = hash(key.hashCode());
這個整數就是哈希碼,然后把哈希碼作為參數傳遞到hash()函數中來進行運算,即散列運算,得到一個int類型的散列值 int i = indexFor(hash, table.length); (transient Entry[] table;) 把散列值和數組的長度來進行運算,最終得到Entry對象要存放到數組的位置(下標)。 hashmap內部的結構是數組加單向鏈表結構,因為不同的key有可能計算出相同的散列值,根據散列值計算出來的存放到數組的下標會沖突(同一個下標值),此時, 如果鍵相同,散列值也一樣,說明是同一個對象,此時會將鍵所對應的舊值用新的鍵值覆蓋掉, 如果散列值一樣,鍵名不一樣,說明是不同的對象,此時會把鍵值對封裝成entry對象放到那個散列值對應的下標位置處, 原來那個entry對象會以鏈表形式鏈接在新創建的entry對象后面
二、hashmap常用方法:
存值:public V put(K key, V value)
取值:public V get(Object key)
獲取所有的鍵:public Set<K> keySet()
獲取所有的值: public Collection<V> values() Returns a {@link Collection} view of the values contained in this map.
取鍵值對的set集合:public Set<Map.Entry<K,V>> entrySet()
map集合大小:public int size()
判斷map是否非空:public boolean isEmpty()
三、示例:
1 package com.iotek.map; 2 3 import java.util.Collection; 4 import java.util.HashMap; 5 import java.util.Map; 6 import java.util.Map.Entry; 7 import java.util.Set; 8 9 public class HashMapDemo1 { 10 public static void main(String[] args) { 11 Map<String, String> map = new HashMap<String, String>(); // 接口的引用變量指向實現類的對象 12 // 創建HashMap對象,也就是創建一個Map容器 13 map.put(null, "張三"); // 添加鍵值對元素 14 map.put(null, "李四"); // 有相同的鍵時,后面添加的鍵對應的值會覆蓋掉之前鍵對應的值 15 map.put("john", "李四"); 16 map.put("rose", "玫瑰"); 17 map.put("mary", "小紅"); 18 System.out.println("1" + map); 19 20 // 獲取map中所有鍵,返回的是一個Set容器,可以用迭代器對象或者foreach來進行輸出 21 Set<String> keys = map.keySet(); 22 System.out.println("******輸出map容器中所有的鍵:"); 23 for (String key : keys) { 24 System.out.print(key + " "); // 用String類型的變量key來遍歷keys容器 25 } 26 27 // 獲取map中所有的值:使用map接口中的values方法,返回Collection接口的實現類 28 Collection<String> values = map.values(); 29 System.out.println("\n******輸出map容器中所有的值:"); 30 for (String value : values) { 31 System.out.print(value + " "); // 用String類型的變量value來遍歷values容器 32 } 33 34 // 得到key的同時,得到key所對應的值 35 System.out.println("\n******用獲取的鍵來得到對應的值並輸出:"); 36 for (String key : keys) { 37 System.out.print(key + "--" + map.get(key)); // 用String類型的變量key來遍歷keys容器 38 } 39 System.out.println("\nmap容器中鍵值對的個數是:" + map.size()); 40 System.out.println("判斷map容器中是否為空:" + map.isEmpty()); 41 42 // map.entrySet()返回的是一個set容器,其中放的是map.Entry內部接口 43 /* 44 * 當我們調用put(key,value)方法時,首先會把key和value封裝到Entry這個靜態內部類中, 45 * 再把Entry對象添加到數組中(哈希表),所以我們想要獲取map中的所有鍵值對,只需要獲取 46 * 數組匯總所有的Entry,接下來調用Entry對象中的getKey 和getValue方法就能獲取鍵值對 47 * 以后想輸出HashMap容器中所有的鍵值對,都可以調用HashMap的 entrySet()方法就可以了!!! 48 */ 49 Set<Entry<String, String>> entrys = map.entrySet(); 50 System.out.println("使用map接口的entrySet()方法獲取map容器中所有的鍵值對:"); 51 for (Entry<String, String> entry : entrys) { 52 System.out.println(entry.getKey() + "-" + entry.getValue()); 53 } 54 map.clear(); 55 System.out.println("判斷map容器中是否為空:" + map.isEmpty()); 56 57 } 58 59 }
map中鍵是對象時,需要重寫對象的hash和equals方法:
1 package com.iotek.map; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 public class HashMapDemo2 { 7 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) { 12 Map<Student, String> map = new HashMap<Student, String>(); 13 map.put(new Student("jay", 20), "張三"); // 1 14 map.put(new Student("lisi", 30), "李四");// 2 15 map.put(new Student("rose", 20), "玫瑰");// 3 16 map.put(new Student("lisi", 30), "陳飛");// 4 17 System.out.println(map.size()); 18 System.out.println(map.toString()); 19 20 /* 21 * Student類中不重寫hashCode() and 22 * equals()方法,此處map.size()值是4,即map中有4個封裝了鍵值對的Entry對象 23 * 重寫了hashCode()和equals()方法后,2和4語句里的學生對象將被判斷為同一個鍵名,因此2位置處的鍵值會被替換掉 24 * 這正是我們需要的,對象相同,應該判定為是同一個鍵,因此,這就是需要重寫hashCode()和equals()方法的原因 25 */ 26 } 27 } 28 29 class Student { 30 private String name; 31 private int age; 32 33 @Override 34 public int hashCode() { 35 final int prime = 31; 36 int result = 1; 37 result = prime * result + age; 38 result = prime * result + ((name == null) ? 0 : name.hashCode()); 39 return result; 40 } 41 /* 42 * 用source中的 Generate hashCode() and equals() 來 生成重寫的hashCode()方法和equals()方法 43 * 只要姓名和年齡相同的學生,那么這個學生對象產生的hashCode值和equals方法的值也是一樣的, 44 * 此時就可以認為是hashmap里放的是同一個對象,那么這兩個相同的Student對象作為鍵時, 45 * 后面添加的Student對象對應的鍵值應該要覆蓋掉前面添加的鍵值 46 */ 47 48 @Override 49 public boolean equals(Object obj) { 50 if (this == obj) 51 return true; 52 if (obj == null) 53 return false; 54 if (getClass() != obj.getClass()) 55 return false; 56 Student other = (Student) obj; 57 if (age != other.age) 58 return false; 59 if (name == null) { 60 if (other.name != null) 61 return false; 62 } else if (!name.equals(other.name)) 63 return false; 64 return true; // 只有當姓名和年齡都一樣時,才返回一個true,表示是同一個對象 65 } 66 67 public Student(String name, int age) { 68 super(); 69 this.name = name; 70 this.age = age; 71 } 72 73 public String getName() { 74 return name; 75 } 76 77 public void setName(String name) { 78 this.name = name; 79 } 80 81 public int getAge() { 82 return age; 83 } 84 85 public void setAge(int age) { 86 this.age = age; 87 } 88 89 @Override 90 public String toString() { 91 return "Student [name=" + name + ", age=" + age + "]"; 92 } 93 94 }
結果:
使用hashmap判斷數組中字符串出現的次數:
1 package com.iotek.map; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.Map.Entry; 6 import java.util.Set; 7 /** 8 * 使用hashmap判斷數組中字符串出現的次數 9 * @author Administrator 10 * 11 */ 12 public class AccountStringDemo { 13 14 public static void main(String[] args) { 15 String[] strs = {"zhangsan","zhangsan","wangwu","chenliu","chenliu","lilei","lilei"}; 16 Map<String,Integer> data = AccountUtil.account(strs); 17 AccountUtil.printData(data); 18 } 19 20 } 21 22 class AccountUtil { 23 public static Map<String,Integer> account(String [] strs) { 24 Map<String,Integer> data = new HashMap<String, Integer>(); 25 for(int i = 0; i < strs.length; i++) { 26 String str = strs[i]; 27 if(data.get(str) == null) { 28 data.put(str, 1); 29 //如果第一次統計到該字符串,將該字符串作為鍵名,其出現的次數作為鍵值,保存在map容器中 30 } else { 31 //如果不是第一次捕獲到該字符串,則data.get(str)!=null,那么將鍵值加1,表示第二次讀取到該字符串 32 data.put(str, data.get(str)+1); 33 } 34 } 35 return data; //將最終的hashmap容器,也就是data返回 36 } 37 38 public static void printData(Map<String,Integer> data) { 39 //使用HashMap的EntrySet()方法,返回map容器:data中的所有鍵值對(全部封裝在Entry中),然后進行打印 40 Set<Entry<String, Integer>> entrys = data.entrySet(); 41 for(Entry<String, Integer> entry : entrys) { 42 System.out.println("字符串" + entry.getKey() + "出現了" + entry.getValue() + "次"); 43 } 44 } 45 46 }