文章目录
- 简述
- Map中key-value特点
- Map接口的常用方法
- Map的主要实现类:HashMap
- HashMap概述
- Map实现类之二:LinkedHashMap
- Map实现类之三:TreeMap
- Map实现类之四:Hashtable(古老实现类)
- Map实现类之五:Properties(古老的类)
简述
-
Map与Collection并列存在。用于保存具有
映射关系
的数据:key-valueCollection
集合称为单列集合,元素是孤立存在的(理解为单身)。Map
集合称为双列集合,元素是成对存在的(理解为夫妻)。
-
Map 中的 key 和 value 都可以是任何引用类型的数据。但常用String类作为Map的“键”。
-
Map接口的常用实现类:
HashMap
、LinkedHashMap
、TreeMap
和``Properties。其中,HashMap是 Map 接口使用
频率最高`的实现类。
Map中key-value特点
这里主要以HashMap为例说明。HashMap中存储的key、value的特点如下:
Map 中的 key用Set来存放
,不允许重复
,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
-
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value,不同key对应的
value可以重复
。value所在的类要重写equals()方法。 -
key和value构成一个entry。所有的entry彼此之间是
无序的
、不可重复的
。
Map接口的常用方法
- 添加、修改操作:
- Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
- void putAll(Map m):将m中的所有key-value对存放到当前map中
- 删除操作:
Object remove(Object key)
:移除指定key的key-value对,并返回valuevoid clear()
:清空当前map中的所有数据
- 元素查询的操作:
Object get(Object key)
:获取指定key对应的valueboolean containsKey(Object key)
:是否包含指定的keyboolean containsValue(Object value)
:是否包含指定的valueint size()
:返回map中key-value对的个数
-boolean isEmpty()
:判断当前map是否为空boolean equals(Object obj)
:判断当前map和参数对象obj是否相等
- 元视图操作的方法:
-Set keySet()
:返回所有key构成的Set集合Collection values()
:返回所有value构成的Collection集合Set entrySet()
:返回所有key-value对构成的Set集合
举例:
import java.util.HashMap;public class TestMapMethod {public static void main(String[] args) {//创建 map对象HashMap map = new HashMap();//添加元素到集合map.put("黄晓明", "杨颖");map.put("李晨", "李小璐");map.put("李晨", "范冰冰");map.put("邓超", "孙俪");System.out.println(map);//删除指定的key-valueSystem.out.println(map.remove("黄晓明"));System.out.println(map);//查询指定key对应的valueSystem.out.println(map.get("邓超"));System.out.println(map.get("黄晓明"));}
}
举例:
public static void main(String[] args) {HashMap map = new HashMap();map.put("许仙", "白娘子");map.put("董永", "七仙女");map.put("牛郎", "织女");map.put("许仙", "小青");System.out.println("所有的key:");Set keySet = map.keySet();for (Object key : keySet) {System.out.println(key);}System.out.println("所有的value:");Collection values = map.values();for (Object value : values) {System.out.println(value);}System.out.println("所有的映射关系:");Set entrySet = map.entrySet();for (Object mapping : entrySet) {//System.out.println(entry);Map.Entry entry = (Map.Entry) mapping;System.out.println(entry.getKey() + "->" + entry.getValue());}
}
Map的主要实现类:HashMap
HashMap概述
- HashMap是 Map 接口
使用频率最高
的实现类。 - HashMap是线程不安全的。允许添加 null 键和 null 值。
- 存储数据采用的哈希表结构,底层使用
一维数组
+单向链表
+红黑树
进行key-value数据的存储。与HashSet一样,元素的存取顺序不能保证一致。 - HashMap
判断两个key相等的标准
是:两个 key 的hashCode值相等,通过 equals() 方法返回 true。 - HashMap
判断两个value相等的标准
是:两个 value 通过 equals() 方法返回 true。
- **练习1:**添加你喜欢的歌手以及你喜欢他唱过的歌曲
例如:
public class SingerTest1 {public static void main(String[] args) {//创建一个HashMap用于保存歌手和其歌曲集HashMap singers = new HashMap();//声明一组key,valueString singer1 = "周杰伦";ArrayList songs1 = new ArrayList();songs1.add("双节棍");songs1.add("本草纲目");songs1.add("夜曲");songs1.add("稻香");//添加到map中singers.put(singer1,songs1);//声明一组key,valueString singer2 = "陈奕迅";List songs2 = Arrays.asList("浮夸", "十年", "红玫瑰", "好久不见", "孤勇者");//添加到map中singers.put(singer2,songs2);//遍历mapSet entrySet = singers.entrySet();for(Object obj : entrySet){Map.Entry entry = (Map.Entry)obj;String singer = (String) entry.getKey();List songs = (List) entry.getValue();System.out.println("歌手:" + singer);System.out.println("歌曲有:" + songs);}}
}
//方式2:改为HashSet实现
public class SingerTest2 {@Testpublic void test1() {Singer singer1 = new Singer("周杰伦");Singer singer2 = new Singer("陈奕迅");Song song1 = new Song("双节棍");Song song2 = new Song("本草纲目");Song song3 = new Song("夜曲");Song song4 = new Song("浮夸");Song song5 = new Song("十年");Song song6 = new Song("孤勇者");HashSet h1 = new HashSet();// 放歌手一的歌曲h1.add(song1);h1.add(song2);h1.add(song3);HashSet h2 = new HashSet();// 放歌手二的歌曲h2.add(song4);h2.add(song5);h2.add(song6);HashMap hashMap = new HashMap();// 放歌手和他对应的歌曲hashMap.put(singer1, h1);hashMap.put(singer2, h2);for (Object obj : hashMap.keySet()) {System.out.println(obj + "=" + hashMap.get(obj));}}
}//歌曲
public class Song implements Comparable{private String songName;//歌名public Song() {super();}public Song(String songName) {super();this.songName = songName;}public String getSongName() {return songName;}public void setSongName(String songName) {this.songName = songName;}@Overridepublic String toString() {return "《" + songName + "》";}@Overridepublic int compareTo(Object o) {if(o == this){return 0;}if(o instanceof Song){Song song = (Song)o;return songName.compareTo(song.getSongName());}return 0;}}
//歌手
public class Singer implements Comparable{private String name;private Song song;public Singer() {super();}public Singer(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Song getSong() {return song;}public void setSong(Song song) {this.song = song;}@Overridepublic String toString() {return name;}@Overridepublic int compareTo(Object o) {if(o == this){return 0;}if(o instanceof Singer){Singer singer = (Singer)o;return name.compareTo(singer.getName());}return 0;}
}
练习2:WordCount统计
需求:统计字符串中每个字符出现的次数
String str = “aaaabbbcccccccccc”;
提示:
char[] arr = str.toCharArray(); //将字符串转换成字符数组
HashMap hm = new HashMap(); //创建双列集合存储键和值,键放字符,值放次数
public class WordCountTest {public static void main(String[] args) {String str = "aaaabbbcccccccccc";char[] arr = str.toCharArray(); // 将字符串转换成字符数组HashMap map = new HashMap(); // 创建双列集合存储键和值for (char c : arr) { // 遍历字符数组if (!map.containsKey(c)) { // 如果不包含这个键map.put(c, 1); // 就将键和值为1添加} else { // 如果包含这个键map.put(c, (int)map.get(c) + 1); // 就将键和值再加1添加进来}}for (Object key : map.keySet()) { // 遍历双列集合System.out.println(key + "=" + map.get(key));}}
}
Map实现类之二:LinkedHashMap
- LinkedHashMap 是 HashMap 的子类
- 存储数据采用的哈希表结构+链表结构,在HashMap存储结构的基础上,使用了一对
双向链表
来记录添加元素的先后顺序
,可以保证遍历元素时,与添加的顺序一致。 - 通过哈希表结构可以保证键的唯一、不重复,需要键所在类重写hashCode()方法、equals()方法。
public class TestLinkedHashMap {public static void main(String[] args) {LinkedHashMap map = new LinkedHashMap();map.put("王五", 13000.0);map.put("张三", 10000.0);//key相同,新的value会覆盖原来的value//因为String重写了hashCode和equals方法map.put("张三", 12000.0);map.put("李四", 14000.0);//HashMap支持key和value为null值String name = null;Double salary = null;map.put(name, salary);Set entrySet = map.entrySet();for (Object obj : entrySet) {Map.Entry entry = (Map.Entry)obj;System.out.println(entry);}}
}
Map实现类之三:TreeMap
- TreeMap存储 key-value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 key-value 对处于
有序状态
。 - TreeSet底层使用
红黑树
结构存储数据 - TreeMap 的 Key 的排序:
自然排序
:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException定制排序
:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
- TreeMap判断
两个key相等的标准
:两个key通过compareTo()方法或者compare()方法返回0。
public class TestTreeMap {/** 自然排序举例* */@Testpublic void test1(){TreeMap map = new TreeMap();map.put("CC",45);map.put("MM",78);map.put("DD",56);map.put("GG",89);map.put("JJ",99);Set entrySet = map.entrySet();for(Object entry : entrySet){System.out.println(entry);}}/** 定制排序** */@Testpublic void test2(){//按照User的姓名的从小到大的顺序排列TreeMap map = new TreeMap(new Comparator() {@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof User && o2 instanceof User){User u1 = (User)o1;User u2 = (User)o2;return u1.name.compareTo(u2.name);}throw new RuntimeException("输入的类型不匹配");}});map.put(new User("Tom",12),67);map.put(new User("Rose",23),"87");map.put(new User("Jerry",2),88);map.put(new User("Eric",18),45);map.put(new User("Tommy",44),77);map.put(new User("Jim",23),88);map.put(new User("Maria",18),34);Set entrySet = map.entrySet();for(Object entry : entrySet){System.out.println(entry);}}
}class User implements Comparable{String name;int age;public User(String name, int age) {this.name = name;this.age = age;}public User() {}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}/*举例:按照age从小到大的顺序排列,如果age相同,则按照name从大到小的顺序排列* */@Overridepublic int compareTo(Object o) {if(this == o){return 0;}if(o instanceof User){User user = (User)o;int value = this.age - user.age;if(value != 0){return value;}return -this.name.compareTo(user.name);}throw new RuntimeException("输入的类型不匹配");}
}
Map实现类之四:Hashtable(古老实现类)
- Hashtable是Map接口的
古老实现类
,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。 - Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构(数组+单向链表),查询速度快。
- 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
- Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
- 与HashMap不同,Hashtable 不允许使用 null 作为 key 或 value。
面试题:Hashtable和HashMap的区别
HashMap:底层是一个哈希表(jdk7:数组+链表;jdk8:数组+链表+红黑树),是一个线程不安全的集合,执行效率高
Hashtable:底层也是一个哈希表(数组+链表),是一个线程安全的集合,执行效率低HashMap集合:可以存储null的键、null的值
Hashtable集合,不能存储null的键、null的值Hashtable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。所以HashMap是Map的主要实现类,Hashtable是Map的古老实现类。Hashtable的子类Properties(配置文件)依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合
Map实现类之五:Properties(古老的类)
-
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
-
由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型
-
存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法
@Test
public void test01() {Properties properties = System.getProperties();String fileEncoding = properties.getProperty("file.encoding");//当前源文件字符编码System.out.println("fileEncoding = " + fileEncoding);
}
@Test
public void test02() {Properties properties = new Properties();properties.setProperty("user","songhk");properties.setProperty("password","123456");System.out.println(properties);
}@Test
public void test03() throws IOException {Properties pros = new Properties();pros.load(new FileInputStream("jdbc.properties"));String user = pros.getProperty("user");System.out.println(user);
}