Map集合
@toc
1、Map集合
Map是地图、映射的意思。生活中地图上的某个点可以映射到实际地理环境中的某个位置,这种映射关系可以用(key,value)的键值对来表示。
Map系列的集合就是用来存储键值对的,java.util.Map
是Map系列接口的根接口,其中包含一个静态内部接口Entry,它是(key,value)映射关系的根接口,Entry接口中提供了getKey和getValue的方法,所有实现Map接口的实现类,也都要用内部类实现Entry接口。
同一个Map中的key是不允许重复的,key和value之间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value,Map中的key和value可以是任何引用类型的数据。一些映射实现可明确保证其顺序,如TreeMap类;另一些映射实现则不保证顺序,如HashMap类。
1.1 Map接口的方法
既然Map是用来存储Entry类的(key,value)键值对的,那么Map接口中自然也封装了所有键值对的通用操作方法:增、删、改、查、遍历。
(1)添加操作
Object put(Object key,Object value)
:put一对(key,value)键值对到当前Map集合中,如果这个key在当前map中不存在,则会新添加。void putAll(Map map)
:将另一个map中的键值对添加到当前Map集合中,如果key相同,则会出现value覆盖的现象。
(2)删除操作
void clear()
:清空当前map集合。Object remove(Object key)
:根据指定的key从当前map中删除一对映射关系。
(3)查询操作
Object get(Object key)
:根据指定的key从当前map中查找其对应的value。boolean containsKey(Object key)
:判断在当前map中是否存在指定的key.boolean containsValue(Object value)
:判断在当前map中是否存在指定的value。boolean isEmpty()
:判断当前map是否为空。
(4)其他方法
int size()
:获取当前map中(key,value)的键值对数。
import java.util.HashMap;
public class MapMethodTest {
public static void main(String[] args) {
HashMap<Object, Object> map = new HashMap<>();
map.put("许仙","白娘子");
map.put("董永","七仙女");
map.put("牛郎","织女");
map.put("许仙","玉兔精");
System.out.println("map:"+map);
System.out.println("键值对数:"+map.size());
System.out.println("是否包含key[许仙]:"+map.containsKey("许仙"));
System.out.println("是否包含value[白娘子]:"+map.containsValue("白娘子"));
System.out.println("获取[许仙]对应的value:"+map.get("许仙"));
map.remove("许仙");
System.out.println("删除[许仙]这对key,value之后的map:"+map);
}
}
1.2 Map集合的遍历
Map接口并没有继承Iterator接口,所以并不支持foreach和Iterator遍历。难道之前Collection集合的遍历方式没有可借鉴之处吗?答案当然是否定的。因为Map接口提供三种collection视图,允许以键集、值集和键-值映射关系集的方式查看某个映射的内容。
(1)分开遍历:又存在两种情况,即单独遍历所有key和单独遍历所有value。
(2)成对遍历:遍历的是映射关系Map.Entry
。Map.Entry
是Map接口的内部接口。每种Map内部都有自己的Map.Entry
的实现类。在Map中存储数据,实际上是将
的数据存储在Map.Entry
接口的实例中,再在Map集合中插入Map.Entry
的实例化对象。
Map接口中有以下三个和遍历相关的方法。
Set keySet()
。Collection values()
。Set entrySet()
。
Map集合遍历的示例代码:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest {
public static void main(String[] args) {
HashMap<Object, Object> map = new HashMap<>();
map.put("许仙","白娘子");
map.put("董永","七仙女");
map.put("牛郎","织女");
System.out.println("所有的key:");
Set<Object> keySet = map.keySet();
for (Object key : keySet) {
System.out.println("\t"+key);
}
System.out.println("所有的value:");
Collection<Object> values = map.values();
for (Object value : values) {
System.out.println("\t"+value);
}
System.out.println("所有的映射关系:");
Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
for (Map.Entry<Object, Object> entry : entrySet) {
System.out.println("\t"+entry);
}
}
}
1.3 Map接口的实现类
Map接口常用的实现类有HashMap
、TreeMap
、LinkedHashMap
和Properties
。其中HashMap是Map接口使用频率最高的实现类。接下来介绍下这几个类的主要特点。
1.3.1 HashMap和Hashtable的区别与联系
HashMap和Hashtable都是哈希表,HashMap和Hashtable的区别如下表所示。
表 | 底层结构 | 线程安全(同步) | 版本 | 效率 | key,value是否允许为null |
---|---|---|---|---|---|
HashMap | 哈希表 | 不安全(不同步) | 较新 | 较高 | 允许 |
Hashtable | 哈希表 | 安全(同步) | 较老 | 较低 | 不允许 |
使用HashMap的示例代码(添加员工姓名为key,薪资为value):
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapTest {
public static void main(String[] args) {
HashMap<Object, Object> map = new HashMap<>();
map.put("张三",10000);
map.put("李四",14000);
map.put(null,null);
Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
for (Map.Entry<Object, Object> object : entrySet) {
System.out.println(object);
}
}
}
1.3.2 LinkedHashMap
LinkedHashMap
是HashMap
的子类,此实现与HashMap
的不同之处在于,LinkedHashMap
维护了一个双向链表,此链表定义了迭代顺序,此迭代顺序通常就是将键插入映射中的顺序。
使用LinkedHashMap
的示例代码:
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class LinkedHashMapTest {
public static void main(String[] args) {
LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
map.put("张三",10000);
map.put("李四",14000);
//遍历发现,可以体现添加顺序,这点和HashMap不同
Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
for (Map.Entry<Object, Object> object : entrySet) {
System.out.println(object);
}
}
}
1.3.3 TreeMap
TreeMap的集合是基于红黑树(Red-Black tree)的可导航NavigableMap实现的。TreeMap中的映射关系要么根据其key键的自然顺序进行排序,要么根据创建TreeMap对象提供给key键的定制排序Comparator接口实现类进行排序,具体取决于使用的构造方法。
TreeMap使用key的自然排序的示例代码(其中String类实现了Comparable接口):
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* TreeMap使用key的自然排序
*/
public class TreeMapTest1 {
public static void main(String[] args) {
TreeMap<Object, Object> map = new TreeMap<>();
//String实现了Comparable接口,默认按照Unicode编码值排序
map.put("Jack",11000);
map.put("Alice",12000);
map.put("zhangsan",13000);
map.put("baitao",14000);
map.put("Lucy",15000);
Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
for (Map.Entry<Object, Object> object : entrySet) {
System.out.println(object);
}
}
}
TreeMap使用定制排序Comparator的示例代码:
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* TreeMap使用定制排序Comparator
*/
public class TreeMapTest2 {
public static void main(String[] args) {
//指定定值比较器Comparator,按照Unicode编码值排序,但是忽略大小写
TreeMap<Object, Object> map = new TreeMap<>(new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
return s1.compareToIgnoreCase(s2);
}
});
map.put("Jack",11000);
map.put("Alice",12000);
map.put("zhangsan",13000);
map.put("baitao",14000);
map.put("Lucy",15000);
Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
for (Map.Entry<Object, Object> object : entrySet) {
System.out.println(object);
}
}
}
1.3.4 Properties
Properties是Hashtable的子类,Properties中存储的数据可保存在流中或从流中加载。Properties的特殊之处在于,它的每个key及其对应的value都是一个字符串。在存取数据时,建议使用setProperty(String key,String value)
方法和getProperty(String key)
方法。
使用Properties的示例代码:
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) {
Properties properties = System.getProperties();
String value = properties.getProperty("file.encoding");//当前源文件字符编码
System.out.println(value);
}
}
1.4 企业面试题
案例需求:有一个字符串,它是一句话,包含了空格等标点符号,统计该字符串中出现次数最多的字母和该字母出现的次数,字母不区分大小写形式。请至少使用两种方法来实现。
方案一:
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
/**
* 有一个字符串,它是一句话,包含了空格等标点符号,统计该字符串中出现次数最多的字母和该字母出现的次数,
* 字母不区分大小写形式。
*/
public class MapExer1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入一串字符:");
String strings = input.nextLine();
//匹配不在a-z范围内的任意字符,替换为空串
strings.toLowerCase().replaceAll("[^a-z]","");
HashMap<Object, Object> map = new HashMap<>();
char[] arr = strings.toCharArray();
for (int i = 0; i < arr.length; i++) {
if(map.containsKey(arr[i])){
Integer count = (Integer) map.get(arr[i]);
map.put(arr[i],count+1);
}else{
map.put(arr[i],1);
}
}
int maxCount=0;
Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
for (Map.Entry<Object, Object> object : entrySet) {
Map.Entry entry = (Map.Entry)object;
Character key= (Character) entry.getKey();
Integer value=(Integer)entry.getValue();
if(value>maxCount){
maxCount=value;
}
}
//考虑到最高次数有相同的多个字符
entrySet= map.entrySet();
for (Map.Entry<Object, Object> object : entrySet) {
Map.Entry entry=(Map.Entry) object;
Character key=(Character)entry.getKey();
Integer value=(Integer)entry.getValue();
if(value==maxCount){
System.out.println("该字符串中出现次数最多的字母是:"+key+",共出现了:"+maxCount);
}
}
}
}
方案二:
import java.util.Scanner;
public class MapExer2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入一串字符:");
String strings = input.nextLine();
strings = strings.toLowerCase().replaceAll("[^a-z]", "");
char[] letterCounts = new char[26];
char[] arr = strings.toCharArray();
for (int i = 0; i < arr.length; i++) {
letterCounts[arr[i]-97]++;
}
int max=0;
for (int i = 0; i < letterCounts.length; i++) {
if(max<letterCounts[i]){
max=letterCounts[i];
}
}
//考虑到最高次数有相同的多个字母
for(int i=0;i<letterCounts.length;i++){
if(max==letterCounts[i]){
System.out.println("该字符串中出现次数最多的字母是:"+(char)(i+97)+",共出现了:"+max);
}
}
}
}
- 点赞
- 收藏
- 关注作者
评论(0)