一、Map接口概述 点击此处返回总目录 二、Map接口中常用集合概述 三、Map接口的常用方法 四、Map集合的遍历方式 五、HashMap练习 六、LinkedHashMap 七、Hashtable 一、Map接口概述 Map接口也是集合,但是与Collection不一样。Collection每次只能装进去一个对象,而Map集合每次存储两个对象(键值对)。 Collection接口和Map接口没有任何关系。 Map中的集合不能包含重复的键,每个键对应一个值。 二、Map接口中常用集合概述 Map接口中常用的集合为HashMap、LinkedHashMap。 1. HashMap<K,V> 存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。 2. LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。 3. Hashtable<K,V>:慢慢淘汰了。 三、Map接口的常用方法 1. public V put(K key, V value) //添加键值对。如果包含了该键,则替换对应的值。返回值一般为null, 当存储重复键的时候,返回的是被覆盖的值。【例1】 2. public V get(Object key) //获取。如果没有这个键,返回null。【例2】 3. public boolean containsKey(Object key); //看看是否包含这个键。【例4】 4. public V remove(Object key) //如果存在的话,移除。【例3】 5. int size() //返回有几个键值对。【例3】 例1:
package cn.itcast.demo01; import java.util.HashMap; import java.util.Map; public class Test { public static void main(String[] args) { Map<String,Integer> map = new HashMap<String,Integer>(); map.put("liupc", 22); Integer i1 = map.put("li", 23); System.out.println(i1); //null。存储元素一般都是返回null。 System.out.println(map); //{li=23, liupc=22} Integer i2 =map.put("li",11); System.out.println(i2); //23。当存储重复键的时候,返回的是被覆盖的值。 System.out.println(map); //{li=11, liupc=22} } } |
例2:
package cn.itcast.demo02; import java.util.HashMap; import java.util.Map; public class Test { public static void main(String[] args) { Map<String,Integer> map = new HashMap<String,Integer>(); map.put("liu",23); map.put("li",22); System.out.println(map); //{li=22, liu=23} Integer i = map.get("liu"); System.out.println(i); //23 System.out.println(map); //{li=22, liu=23} Integer i2 = map.get("wang"); System.out.println(i2); //null } } |
例3:
package cn.itcast.demo03; import java.util.HashMap; import java.util.Map; public class Test { public static void main(String[] args) { Map<String,Integer> map = new HashMap<String,Integer>(); map.put("liu",23); map.put("li",22); System.out.println(map); //{li=22, liu=23} System.out.println(map.size()); //2 Integer i1 = map.remove("liu"); System.out.println(i1); //23 System.out.println(map); //{li=22} Integer i2 = map.remove("wang"); System.out.println(i2); //null System.out.println(map); //{li=22} } } |
例4:
package cn.itcast.demo01; import java.util.HashMap; import java.util.Map; public class Test4 { public static void main(String[] args) { Map<Integer, Integer> map = new HashMap<>(); map.put(1,3); map.put(2,4); System.out.println(map.containsKey(1)); //true System.out.println(map.containsKey(3)); //false } } |
四、Map集合的遍历方式 方式1:利用键获取值的方式。首先调用Map的keySet()方法,把Map中的所有键存储到一个Set中;然后就可以遍历Set,拿到key了;最后通过get操作获取value的值。【例1】 例1:
package cn.itcast.demo04; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class Test { public static void main(String[] args) { Map<String,Integer> map = new HashMap<String,Integer>(); map.put("liupc", 22); map.put("li", 23); map.put("wang",24); Set<String> set = map.keySet(); //把key存储到一个set中。 //使用迭代器遍历 Iterator<String> it = set.iterator(); while(it.hasNext()){ String key = it.next(); Integer value = map.get(key); System.out.println(key + ":" + value); } //使用增强for循环遍历 for(String i:set){ Integer val = map.get(i); System.out.println(i+":"+val); } } } |
方式2:entrySet()方法。 Map接口中又写了一个接口:Entry(中文翻译为"登记")。Entry是映射关系的接口。方便理解,可以把key-value想成一对夫妻,而Entry就是结婚证。【例2】 Map接口中有方法entrySet(),通过这个方法可以得到一个Set集合,集合中存放的是Entry类型的对象(映射关系的对象,结婚证)。Entry接口的getKey()、getValue()方法可以得到key和value。意思就是每个Key-Value对有一个结婚证,entrySet()方法可以收走所有夫妻的结婚证。然后通过结婚证可以找到夫妻两人。【例2】【例3】 例2:Map()接口的源码
public interface Map<K,V> { .... Set<Map.Entry<K, V>> entrySet(); //通过调用Map的entrySet()方法,可以得到一个集合,集合中存放的是Entry类型的对象。 interface Entry<K,V> { //Map接口中又写了一个接口Entry。表示映射关系。 K getKey(); //Entry接口的对象可以调用getKey()方法获取key。 V getValue(); //也可以获取value。 ...... } .... } |
例3:
package cn.itcast.demo05; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class Test { public static void main(String[] args) { Map<String,Integer> map = new HashMap<String,Integer>(); map.put("aa", 1); map.put("bb", 2); Set<Map.Entry<String,Integer>> set = map.entrySet(); //调用Map集合的entrySet()方法:将集合中的映射关系对象,存储到 Set中。 //迭代器方式: Iterator<Map.Entry<String,Integer>> it = set.iterator(); //迭代Set集合。 while(it.hasNext()){ Map.Entry<String, Integer> entry = it.next(); //获取的Set集合的元素是映射关系的对象。 System.out.println(entry.getKey() + ":"+entry.getValue()); //通过映射关系对象的getkey()、getValue()方法获取key、Value. } //增强for方式: for(Map.Entry<String, Integer> entry : set){ System.out.println(entry.getKey() + ":"+entry.getValue()); } } } |
说明: 1. 这两种方式都要熟练。第一种用的多,第二种复杂一点。 2. 面试题:增强for可以遍历Map么?答:不可以。因为增强for循环是Collection的父接口Iterable提供的方法。而Map不在Iterable下。 那为什么例3中,使用了增强的for遍历了Map呢?答:因为实际上使用增强for遍历了entry的set集合,并没有直接遍历Map。 五、HashMap练习 练习1.使用HashMap存储自定义的对象Person,并遍历。将Person对象当做值。 //Person.java
package cn.itcast.demo06; public class Person { private String name; private int age; public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString(){ return name + "..."+age; } } |
//Test.java
package cn.itcast.demo06; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class Test { public static void main(String[] args) { Person p1 = new Person("aaa",11); Person p2 = new Person("bbb",22); HashMap<String,Person> map = new HashMap<String,Person>(); map.put("AAA",p1); map.put("BBB",p2); //遍历方式一: Set<String> set = new HashSet<String>(); set =map.keySet(); for(String str:set){ System.out.println(str + "..."+map.get(str)); } //遍历方式二 Set<Map.Entry<String,Person>> set1= map.entrySet(); for(Map.Entry<String,Person> entry:set1){ System.out.println(entry.getKey() +"..."+entry.getValue()); } } } |
//结果: BBB...bbb...22 AAA...aaa...11 BBB...bbb...22 AAA...aaa...11 练习2.使用HashMap存储自定义的对象Person,并遍历。将Person对象当做key。 首先来看一下代码: //Person.java
package cn.itcast.demo06; public class Person { private String name; private int age; public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString(){ return name + "..."+age; } } |
//Test.java
package cn.itcast.demo07; import java.util.HashMap; import java.util.Set; import cn.itcast.demo06.Person; public class Test { public static void main(String[] args) { HashMap<Person,String> map= new HashMap<Person,String>(); map.put(new Person("aaa",11), "haha"); map.put(new Person("aaa",11), "haha"); //这两个Person对象都是新new的,不是同一个对象。 Set<Person> set = map.keySet(); for(Person p :set){ System.out.println(p + ".." +map.get(p)); } } } |
运行结果: aaa...11..haha aaa...11..haha 运行结果发现,“同一个”key出现了两次。这不符合我们的期望。我们期望name和age都相等时,就认为是同一个key,在map中只能存一次。 为了能够达到我们的效果,应当重写Person的hashCode()方法和equals()方法。 //Person.java
package cn.itcast.demo08; public class Person { private String name; private int age; public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString(){ return name + "..."+age; } public int hashCode(){ //熟练之后,可以自动生成重写hashCode()的代码。 String str = name + age; return str.hashCode(); } public boolean equals(Object obj) { //熟练之后,可以自动生成重写equals()的代码。 if(obj == null){ return false; } if(this == obj){ return true; } if (obj instanceof Person){ Person p = (Person)obj; return name.equals(p.name) && age == p.age; }else{ return false; } } } |
//Test.java
package cn.itcast.demo08; import java.util.HashMap; import java.util.Set; public class Test { public static void main(String[] args) { HashMap<Person,String> map= new HashMap<Person,String>(); map.put(new Person("aaa",11), "haha"); map.put(new Person("aaa",11), "hehe"); Set<Person> set = map.keySet(); for(Person p :set){ System.out.println(p + ".." +map.get(p)); } } } |
运行结果: aaa...11..hehe 六、LinkedHashMap LinkedHashMap继承自HashMap。是有顺序的,存进去什么顺序,遍历就是什么顺序。 例:
package cn.itcast.demo09; import java.util.LinkedHashMap; public class Test { public static void main(String[] args) { LinkedHashMap<String,Integer> map =new LinkedHashMap<String,Integer>(); map.put("bbb", 32); map.put("aaa", 22); map.put("ccc", 11); for(String s:map.keySet()){ System.out.println(s+"..."+map.get(s)); } } } |
运行结果: bbb...32 aaa...22 ccc...11 七、Hashtable Hashtable是Map接口的又一个实现类。 底层数据结构也是哈希表。特点和HashMap是一样的。 与HashMap的区别是:HashMap是线程不安全的,运行速度快;Hashtable是线程安全的,运行速度慢。所以,Hashtable的命运和Vector集合一样,从JDK1.2开始,Hashtable被更先进的HashMap取代。已经慢慢被抛弃,郁郁而终了~ 还有一个区别,一定要知道,面试的时候可能会问: HashMap 允许存储null值,null键。Hashtable不允许存储null值、null键。【例1】 虽然Hashtable不怎么用了,但是他的子类Properties依然还活跃在开发舞台。他可以和后面的IO流配合,实现数据的持久存储。等到IO的时候单独讲~ 例1:
package cn.itcast.demo10; import java.util.HashMap; import java.util.Hashtable; public class Test { public static void main(String[] args) { HashMap<String,String> map = new HashMap<String,String>(); map.put(null, "aa"); map.put("11", null); System.out.println(map.get(null)); //aa System.out.println(map.get("11")); //null Hashtable<String,String> table = new Hashtable<String,String>(); table.put("11", "aa"); //table.put(null, "bb"); //这句错误。不能以null为键。 //table.put("22",null); //这句错误。不能以nul为值。 System.out.println(table.get("11")); //aa //System.out.println(table.get(null)); //System.out.println(table.get("22")); } } |
|