Map集合
Map对象是将键映射到值的对象, 一个映射不能包含重复的键,每个键最多只能映射到一个值,并且它也是一个接口,因此它不能直接实例化,但可以用多态的方式创建对象。
Map接口和Collection接口的区别
Map接口 | Collection接口 |
---|---|
Map是双列的 | Collection是单列的 |
Map的键值是唯一的 | Collection的子体系Set是唯一的 |
Map集合的数据结构针对键有效 | Collection集合的数据结构针对元素有效 |
Map集合的常用功能
V put(K key,V value) | 添加元素,其实也可以用它来替换相同键值的映射值 |
---|---|
void clear() | 移除所有元素 |
V remove(Object key) | 移除指定键值对(键值和映射值),并返回该键值所对的映射值 |
boolean containsKey(Object key) | 判断是否包含该键值 |
boolean containsValue(Object value) | 判断是否包含该映射值 |
boolean isEmpty() | 判断是否为空 |
Set<Map.Entry<K,V>> entrySet() | 返回一个键值对的Set集合,可以用它来遍历 |
V get(Object key) | 得到键值所对应的映射值 |
Set<K> keySet() | 返回键值的Set集合 |
Collection<V> values() | 返回映射值的Collection集合 |
int size() | 返回集合中键值对的对数 |
体系图
HashMap集合
HashMap集合是Map接口的实现类,其底层数据结构是哈希表(哈希表:数组+链表,这是在JDK1.8之前,而在JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间),其中允许插入null键 null值,并且它是唯一和无序的,它的键值唯一的保证是重写hashCode方法和equals方法,这和HashSet集合的特点是一样的。(如果想具体了解可以看一下此文章:https://www.cnblogs.com/xiaoxi/p/7233201.html)
LinkedHashMap集合
LinkedHashMap集合是Map接口的实现类,其底层数据结构是链表和哈希表,其中的元素有序且唯一,链表是保证元素的有序性,哈希表保证元素的唯一性,这和LinkedHashSet集合的特点的一样的。
TreeMap集合
TreeMap集合是Map接口的实现类,键数据结构是红黑树,可保证键的排序和唯一性 ,排序分为自然排序和比较器排序(可参考TreeSet集合,其用法相同) ,线程是不安全但效率比较高,其中的键不允许插入null,这和TreeSet集合的特点是一样的。
代码演示
1、用TreeMap模拟注册、登录(输入三次错误密码和用户名,就退出程序,注册格式不正确,就继续注册)。
Check类
public class Check {
//判断用户名格式是否正确
public boolean checkName(String s){
//用户名格式为数字、字母或下划线,但开头不能为0,范围在6~16位
String str="[1-9a-zA-Z][0-9a-z_A-Z]{5,15}";
return s.matches(str);
}
//判断密码格式是否正确
public boolean checkPwd(String s){
//密码只能是数字,但开头不能为0,范围在6~16位
String str="[1-9][0-9]{5,15}";
return s.matches(str);
}
}
Login类
import java.util.*;
public class Login {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//创建一个TreeMap对象,用来保存用户名和密码
TreeMap<String, String> treeMap = new TreeMap<>();
Check check = new Check();
//定义一个计数值,为了计算输入密码和用户名的次数,如果输入错误3次,就会退出程序
int count=3;
while(true){
System.out.println("--------------注册1--登录2--退出3--------------");
System.out.println("请选择功能(数字):");
int t=sc.nextInt();
switch (t){
case 1:
while (true){
System.out.println("请输入注册用户名(字母、数字、下划线):");
String usrname=sc.next();
System.out.println("请输入注册密码(纯数字):");
String password=sc.next();
//如果用户名和密码格式都正确,则注册成功,如果格式不正确,则输出不正确的提示,然后继续注册
if(check.checkName(usrname)==true&&check.checkPwd(password)==true){
//把用户名和密码保存到TreeMap对象中
treeMap.put(usrname,password);
System.out.println("注册成功");
break;
}else if(check.checkName(usrname)==true&&check.checkPwd(password)==false){
System.out.println("密码格式不正确!");
}else if(check.checkName(usrname)==false&&check.checkPwd(password)==true){
System.out.println("用户名格式不正确!");
}else{
System.out.println("用户名和密码格式不正确!");
}
}
break;
case 2:
while(true){
System.out.println("请输入用户名:");
String y = sc.next();
System.out.println("请输入密码:");
String m = sc.next();
//如果密码和用户名都正确,那么登陆成功退出程序,否则登录失败,继续输入,直到3次机会用完,就退出程序
if(treeMap.containsKey(y)==true&&m.equals(treeMap.get(y))==true){
System.out.println("登录成功!");
System.exit(0);
}else if(count==0){
System.out.println("请明天再试!");
System.exit(0);
} else{
System.out.println("用户名或密码输入错误!");
System.out.println("你还有"+count+"次机会");
}
count--;
}
case 3:
default:
System.exit(0);
}
}
}
}
结果
--------------注册1--登录2--退出3--------------
请选择功能(数字):
1
请输入注册用户名(字母、数字、下划线):
lijiayu
请输入注册密码(纯数字):
123456
注册成功
--------------注册1--登录2--退出3--------------
请选择功能(数字):
1
请输入注册用户名(字母、数字、下划线):
lanshuqi
请输入注册密码(纯数字):
123456
注册成功
--------------注册1--登录2--退出3--------------
请选择功能(数字):
2
请输入用户名:
lanshuqi
请输入密码:
123456
登录成功!
2、键盘输入字符串,并计算字符出现的次数(并按照 字母(出现次数) 格式输出,如:s(2))。
import java.util.HashMap;
import java.util.Scanner;
public class Sum {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//创建HashMap对象,键值是字母,映射值是字母出现的次数
HashMap<Character, Integer> hashMap = new HashMap<>();
System.out.println("Please input number:");
String str=sc.next();
//把字符串转变为字符数组
char[] chars = str.toCharArray();
//遍历字符数组
for (char c : chars) {
//如果HashMap集合中没有这个字符,就把该字符放入集合中,这时它出现的次数为1
if(!hashMap.containsKey(c)){
hashMap.put(c,1);
}else {
//如果HashMap集合中有这个字符,就取出该字符出现的次数(映射值),然后给该值加1,最后放入集合中,覆盖之前的映射值
Integer i = hashMap.get(c);
i++;
hashMap.put(c,i);
}
}
//创建一个StringBuffer对象,构造输出格式
StringBuffer buffer = new StringBuffer();
//遍历HashMap集合,得到里面的键值和映射值
for (Character character : hashMap.keySet()) {
buffer.append(character).append("(").append(hashMap.get(character)).append(")").append(" ");
}
System.out.println(buffer);
}
}
结果
Please input number:
asdfdfsd
a(1) s(2) d(3) f(2)
3、用HashMap嵌套HashMap,输出以下格式。
基础班
张三 20
李四 22
就业班
王五 21
赵六 23
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class BianLi3 {
public static void main(String[] args) {
//创建一个HashMap对象,键值为姓名,映射值为年龄
HashMap<String, Integer> hashMap1 = new HashMap<>();
hashMap1.put("张三",20);
hashMap1.put("李四",22);
//创建一个HashMap对象,键值为姓名,映射值为年龄
HashMap<String, Integer> hashMap2 = new HashMap<>();
hashMap2.put("王五",21);
hashMap2.put("赵六",23);
//创建一个HashMap对象,键值为班级,映射值HashMap对象
HashMap<String, HashMap<String, Integer>> map = new HashMap<>();
//将键值和映射值放入HashMap集合中
map.put("基础班",hashMap1);
map.put("就业班",hashMap2);
//调用entrySet()方法返回键值对(键值和映射值是一对)集合,为了遍历集合,输出班级
Set<Map.Entry<String, HashMap<String, Integer>>> entries = map.entrySet();
//遍历键值对集合
for (Map.Entry<String, HashMap<String, Integer>> entry : entries) {
//输出键值,也就是班级
System.out.println(entry.getKey());
//再调用entrySet()方法返回键值对,为了遍历,输出姓名和年龄
Set<Map.Entry<String, Integer>> set = entry.getValue().entrySet();
for (Map.Entry<String, Integer> integerEntry : set) {
//因为这个HashMap集合是嵌套的因此遍历两次才可以遍历到最里面的姓名和年龄
System.out.println("\t"+integerEntry.getKey()+"\t\t"+integerEntry.getValue());
}
}
}
}
结果
就业班
王五 21
赵六 23
基础班
李四 22
张三 20