Map集合為映射類型,映射與集和清單有明顯的差別,映射中的每個對象都是成對存在的。映射中存儲的每個對象都有一個相應的鍵(Key)對象,在檢索對象時必須通過相應的鍵對象來擷取值(value)對象,類似于在字典中查找單詞一樣,是以要求鍵對象必須是惟一的。鍵對象還決定了存儲對象在映射中的存儲位置,但并不是鍵對象本身決定的,需要通過一種散列技術進行處理,進而産生一個被稱作散列碼的整數值,散列碼通常用作一個偏置量,該偏置量是相對于配置設定給映射的記憶體區域的起始位置的,由此來确定存儲對象在映射中的存儲位置。理想情況下,通過散列技術得到的散列碼應該是在給定範圍内均勻分布的整數值,并且每個鍵對象都應該得到不同的散列碼。 (1)Map集合的用法 Map集合包括Map接口以及Map接口的所有實作類。由Map接口提供用來操作集合的常用方法如下表5所示:

Map接口的常用實作類有HashMap和TreeMap,HashMap類通過哈希碼對其内部的映射關系進行快速查找,而TreeMap類中的映射關系存在一定的順序,如果希望在周遊集合時是有序的,應該使用由TreeMap類實作的Map集合,否則建議使用由HashMap類實作的Map集合,因為由HashMap類實作的Map集合對于添加和删除映射關系更高效。 Map集合允許值對象為null,并且沒有個數限制,是以當get()方法的傳回值為null時,可能有兩種情況,一種是在集合中沒有該鍵對象,另一種是該鍵對象沒有映射任何值對象,即值對象為null。是以,在Map集合中不應該利用get()方法來判斷是否存在某個鍵,而應該利用containsKey()方法來判斷。 例如: 源檔案:TestMap.java
import java.util.*;
public class TestMap{
public static void main(String args[]){
Map map = new HashMap();
System.out.println("map集合是否為空:"+map.isEmpty());
map.put(22015,null);
System.out.println("map集合是否為空:"+map.isEmpty());
map.put(22016,"馬先生");
System.out.println("map集合是否為空:"+map.isEmpty());
System.out.println("get()方法的傳回結果:");
System.out.print(map.get(22015));
System.out.print(" "+map.get(22016));
System.out.println(" "+map.get(22017));
System.out.println("containsKey()方法的傳回結果:");
System.out.print(map.containsKey(22015));
System.out.print(" "+map.containsKey(22016));
System.out.println(" "+map.containsKey(22017));
System.out.println("map集合中映射的個數:"+map.size());
map.remove(22015);
System.out.println("map集合中映射的個數:"+map.size());
}
}
import java.util.*;
public class TestMap{
public static void main(String args[]){
Map map = new HashMap();
System.out.println("map集合是否為空:"+map.isEmpty());
map.put(22015,null);
System.out.println("map集合是否為空:"+map.isEmpty());
map.put(22016,"馬先生");
System.out.println("map集合是否為空:"+map.isEmpty());
System.out.println("get()方法的傳回結果:");
System.out.print(map.get(22015));
System.out.print(""+map.get(22016));
System.out.println(""+map.get(22017));
System.out.println("containsKey()方法的傳回結果:");
System.out.print(map.containsKey(22015));
System.out.print(""+map.containsKey(22016));
System.out.println(""+map.containsKey(22017));
System.out.println("map集合中映射的個數:"+map.size());
map.remove(22015);
System.out.println("map集合中映射的個數:"+map.size());
}
}
程式的運作結果如下: map集合是否為空:true map集合是否為空:false map集合是否為空:false get()方法的傳回結果: null 馬先生 null containsKey()方法的傳回結果: true true false map集合中映射的個數:2 map集合中映射的個數:1
(2)使用HashMap類 HashMap類實作了Map接口,由HashMap類實作的Map集合允許以null作為鍵對象,但是因為鍵對象不可以重複,是以這樣的鍵對象隻能有一個。如果經常需要添加、删除和定位映射關系,建議利用HashMap類實作Map集合,不過在周遊集合時得到的映射關系是無序的。 在使用由HashMap類實作的Map集合時,如果想有效地使用,就必須重寫作為主鍵對象類的hashCode()方法,在重寫hashCode()方法時,有兩條基本原則: ● 不唯一原則:不必為每個對象生成一個惟一的哈希碼,隻要通過hashCode()方法生成的哈希碼,利用get()方法能夠得到利用put()方法添加的映射關系即可。 ● 分散原則:生成哈希碼的算法應盡量使哈希碼的值分散一些,不要将很多哈希碼值都集中在一個範圍内,這樣有利于提高由HashMap類實作的Map集合的性能。 例如: 源檔案:PK_person.java
public class PK_person{
private String prefix;
private long number;
public String setPrefix(){
return prefix;
}
public void setPrefix(String prefix){
this.prefix = prefix;
}
public long getNumber(){
return number;
}
public void setNumber(long number){
this.number = number;
}
public String getPK(){
return this.prefix+"_"+this.number;
}
public void setPK(String pk){
int i = pk.indexOf("_");
this.prefix = pk.substring(0,i);
this.number = new Integer(pk.substring(i));
}
}
public class PK_person{
private String prefix;
private long number;
public String setPrefix(){
return prefix;
}
public void setPrefix(String prefix){
this.prefix = prefix;
}
public long getNumber(){
return number;
}
public void setNumber(long number){
this.number = number;
}
public String getPK(){
return this.prefix+"_"+this.number;
}
public void setPK(String pk){
int i = pk.indexOf("_");
this.prefix = pk.substring(0,i);
this.number = new Integer(pk.substring(i));
}
}
源檔案:Person.java
public class Person{
private String name;
private PK_person number;
public Person(PK_person number,String name){
this.number = number;
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public PK_person getNumber(){
return number;
}
public void setNumber(PK_person number){
this.number = number;
}
}
public class Person{
private String name;
private PK_person number;
public Person(PK_person number,String name){
this.number = number;
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public PK_person getNumber(){
return number;
}
public void setNumber(PK_person number){
this.number = number;
}
}
源檔案:TestMap.java
import java.util.*;
public class TestMap{
public static void main(String args[]){
Map map = new HashMap();
PK_person pk_person1 = new PK_person();
pk_person1.setPrefix("MR");
pk_person1.setNumber(22015);
map.put(pk_person1,new Person(pk_person1,"馬先生"));
PK_person pk_person2 = new PK_person();
pk_person2.setPrefix("MR");
pk_person2.setNumber(22015);
Person person = map.get(pk_person2);
if(person == null){
System.out.println("該鍵對象不存在!");
}
else{
System.out.println(person.getNumber().getNumber()+" "+person.getName());
}
}
}
import java.util.*;
public class TestMap{
public static void main(String args[]){
Map map = new HashMap();
PK_person pk_person1 = new PK_person();
pk_person1.setPrefix("MR");
pk_person1.setNumber(22015);
map.put(pk_person1,new Person(pk_person1,"馬先生"));
PK_person pk_person2 = new PK_person();
pk_person2.setPrefix("MR");
pk_person2.setNumber(22015);
Person person = map.get(pk_person2);
if(person == null){
System.out.println("該鍵對象不存在!");
}
else{
System.out.println(person.getNumber().getNumber()+""+person.getName());
}
}
}
程式的運作結果如下: 該鍵對象不存在! 無論執行多少次,輸出的資訊都為“該鍵對象不存在!”,即在集合中不存在該鍵對象。這是因為沒有重寫java.lang.Object()類中的hashCode()和equals()方法,equals()方法預設比較兩個對象的位址,是以即使這兩個鍵對象的内容完全相同,也不認為是同一個對象,重寫後的hashCode()和equals()方法的完整代碼如下:
public int hashCode(){//重寫hashCode()方法
return (int)(number + prefix.hashCode());
}
public boolean equals(Object obj){//重寫equals()方法
if(obj == null){
return false;
}
if(getClass()!=obj.getClass()){
return false;
}
if(this == obj){
return true;
}
final PK_person other = (PK_person)obj;
if(this.hashCode()!=other.hashCode()){
return false;
}
return true;
}
public int hashCode(){//重寫hashCode()方法
return (int)(number + prefix.hashCode());
}
public boolean equals(Object obj){//重寫equals()方法
if(obj == null){
return false;
}
if(getClass()!=obj.getClass()){
return false;
}
if(this == obj){
return true;
}
final PK_person other = (PK_person)obj;
if(this.hashCode()!=other.hashCode()){
return false;
}
return true;
}
重寫PK_person類中的hashCode()和equals()方法後,再次執行程式,結果如下: 2015 馬先生
(3)使用TreeMap類 TreeMap類不僅實作了Map接口,還實作了Map接口的子接口java.util.SortedMap。由TreeMap類實作的Map集合不允許鍵對象為null,因為集合中的映射關系是根據鍵對象按照一定順序排列的,TreeMap類通過實作SortedMap接口得到的方法如下表6所示:
在添加、删除和定位映射關系上,TreeMap類要比HashMap類的性能差一些,但是其中的映射關系具有一定的順序,如果不需要一個有序的集合,則建議使用HashMap類;如果需要進行有序的周遊輸出,則建議使用TreeMap類,在這種情況下,可以先使用由HashMap類實作的Map集合,在需要順序輸出時,在利用現有的HashMap類的執行個體建立一個具有完全相同映射關系的TreeMap類型的執行個體。 例如: 源檔案:Person.java
public class Person{
private String name;
private long id_card;
public Person(String name,long id_card){
this.id_card = id_card;
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public long getId_card(){
return id_card;
}
public void setId_card(long id_card){
this.id_card = id_card;
}
}
public class Person{
private String name;
private long id_card;
public Person(String name,long id_card){
this.id_card = id_card;
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public long getId_card(){
return id_card;
}
public void setId_card(long id_card){
this.id_card = id_card;
}
}
源檔案:TestMap.java
import java.util.*;
public class TestMap{
public static void main(String args[]){
Person p1 = new Person("馬先生",22015);
Person p2 = new Person("李小姐",22018);
Person p3 = new Person("馬先生",22016);
Map map = new HashMap();
map.put(22015,p1);
map.put(22018,p2);
map.put(22016,p3);
System.out.println("由HashMap類實作的Map集合,無序:");
Iterator it1 = map.keySet().iterator();
while(it1.hasNext()){
Person person = map.get(it1.next());
System.out.println(person.getId_card()+" "+person.getName());
}
System.out.println("由TreeMap類實作的Map集合,鍵對象升序:");
TreeMap treeMap1 = new TreeMap();
treeMap1.putAll(map);
Iterator it2 = treeMap1.keySet().iterator();
while(it2.hasNext()){
Person person = treeMap1.get(it2.next());
System.out.println(person.getId_card()+" "+person.getName());
}
System.out.println("由TreeMap類實作的Map集合,鍵對象降序:");
TreeMap treeMap2 = new TreeMap(Collections.reverseOrder());
treeMap2.putAll(map);
Iterator it3 = treeMap2.keySet().iterator();
while(it3.hasNext()){
Person person = treeMap2.get(it3.next());
System.out.println(person.getId_card()+" "+person.getName());
}
}
}
import java.util.*;
public class TestMap{
public static void main(String args[]){
Person p1 = new Person("馬先生",22015);
Person p2 = new Person("李小姐",22018);
Person p3 = new Person("馬先生",22016);
Map map = new HashMap();
map.put(22015,p1);
map.put(22018,p2);
map.put(22016,p3);
System.out.println("由HashMap類實作的Map集合,無序:");
Iterator it1 = map.keySet().iterator();
while(it1.hasNext()){
Person person = map.get(it1.next());
System.out.println(person.getId_card()+""+person.getName());
}
System.out.println("由TreeMap類實作的Map集合,鍵對象升序:");
TreeMap treeMap1 = new TreeMap();
treeMap1.putAll(map);
Iterator it2 = treeMap1.keySet().iterator();
while(it2.hasNext()){
Person person = treeMap1.get(it2.next());
System.out.println(person.getId_card()+""+person.getName());
}
System.out.println("由TreeMap類實作的Map集合,鍵對象降序:");
TreeMap treeMap2 = new TreeMap(Collections.reverseOrder());
treeMap2.putAll(map);
Iterator it3 = treeMap2.keySet().iterator();
while(it3.hasNext()){
Person person = treeMap2.get(it3.next());
System.out.println(person.getId_card()+""+person.getName());
}
}
}
程式的運作結果如下: 由HashMap類實作的Map集合,無序: 22016 馬先生 22018 李小姐 22015 馬先生 由TreeMap類實作的Map集合,鍵對象升序: 22015 馬先生 22016 馬先生 22018 李小姐 由TreeMap類實作的Map集合,鍵對象降序: 22018 李小姐 22016 馬先生 22015 馬先生