智渔课堂官方免费教程三十三:Java集合框架之Map集合

时间:2021-09-07 15:08:34

Map接口

Map集合采用键值对(key-value)的方式存储数据,其中键不可以重复、值可以重复。
常用类有HashMap、TreeMap和Properties

HashMap类

假如,现在我有一个集合,集合中存储着一批WiFi的名称和密码,现在要求通过名称快速找到密码。这样的需求使用List集合实现起来非常困难,Java为我们提供了另一种形式的集合,可以很好的解决这样的问题。就是Map集合。
实例:package map.hashMap;
import java.util.HashMap;
import java.util.Map;
/**
* 演示HashSet
* @author 学霸联盟 - 赵灿
*/
public class HashMapDemo {
public static void main(String[] args) {
//创建集合对象
Map map = new HashMap();
/*
* 注意:map集合添加元素的方法是put,不是add
* 前一个参数代表key(键),后一个参数代表value(值)
*/
map.put("wifiName1", "password1");
/*
* 当出现key重复时,后面的值会将前面的值覆盖
* 而value重复时,无影响
*/
map.put("wifiName2", "password2");
map.put("wifiName2", "password3");
map.put("wifiName3", "password3");
//获取集合的长度,加入4次,长度为3
int size = map.size();
System.out.println(size);
//获取key为"wifiName2"的value
String wifi2 = (String)map.get("wifiName2");
System.out.println(wifi2);
//两种方式转换成String都可以
String wifi3 = map.get("wifiName3").toString();
System.out.println(wifi3);
}
}
运行结果:
3
password3
password3

注意:Set集合会将加入的元素存储在Map集合的key上,如果出现重复不会覆盖,保留前一个;但是Map集合中加入元素出现key相同的情况时,key不会覆盖,但是value会被后加入的value覆盖。

上面我们讲到向Set集合中添加元素时,会创建Node(节点),在节点的key中保持着当前加入的元素。在该节点中还有一个value属性,同样保存一个Object对象,只不过Set中没有使用这个value属性。而Map集合中需要存储两个值key和value,其中我们调用put方法时传入的第一个参数保存在Node对象的属性key上,传入的第二个参数就是保存在Node对象的属性value上。
由此一来,在使用key获取Map集合中对应的value时,先通过在hash表中找到key所在的Node对象,然后就返回Node对象中value的值,这样就得到了key所对应的value值了。

Map集合一些常用方法的演示
实例:package map.hashMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
/**
* 演示HashMap类中的一些常用方法
* @author 学霸联盟 - 赵灿
*/
public class HashMapMethodDemo {
public static void main(String[] args) {
//创建两个班级class1和class2
HashMap class1 = new HashMap();
HashMap class2 = new HashMap();
/*
* 向两个班级中各添加三个学生和成绩
* 1班中有个叫“王五”的同学,成绩是50分
* 2班中也有个叫“王五”的同学,成绩是90分
*/
class1.put("张三", "80分");
class1.put("李四", "60分");
class1.put("王五", "50分");

class2.put("赵四", "80分");
class2.put("陈六", "0分");
class2.put("王五", "90分");
//判断1班有没有姓名叫“王五”的同学
boolean containsKey = class1.containsKey("王五");
System.out.println("集合class1中有没有key是王五:" + containsKey);
System.out.println("-------------------------------------");
//判断1班有没有成绩是90分的同学
boolean containsValue = class1.containsValue("90分");
System.out.println("集合class1中有没有value是90分:" + containsValue);
System.out.println("-------------------------------------");
//将2班同学合并到一班
class1.putAll(class2);
//获取班级人数(集合长度)
int size = class1.size();
System.out.println("合并后的班级总人数:" + size);
System.out.println("-------------------------------------");
//获取1班所有同学的姓名
Set nameSet = class1.keySet();
//增强for循环输出所有姓名
for (Object o : nameSet) {
System.out.print(o + " ");
}
System.out.println();
System.out.println("-------------------------------------");
//获取1班所有同学的成绩
Collection scores = class1.values();
//增强for循环输出所有成绩
for (Object o : scores) {
System.out.print(o + " ");
}
System.out.println();
System.out.println("-------------------------------------");
//获取1班所有同学的姓名和成绩
Set nameAndScoreSet = class1.entrySet();
//增强for循环输出所有成绩
for (Object o : nameAndScoreSet) {
System.out.print(o + " ");
}
System.out.println();
System.out.println("-------------------------------------");
//获取王五的成绩
Object wangwuScore = class1.get("王五");
System.out.println("合并后王五的成绩:" + wangwuScore);
System.out.println("-------------------------------------");
//删除key为“王五”的value
class1.remove("王五");
//删除“王五”后
System.out.println("王五的成绩:" + class1.get("王五"));
System.out.println("是否包含叫“王五”的key:" + class1.containsKey("王五"));
System.out.println("是否包含“90分”的value:" + class1.containsValue("90分"));
System.out.println("-------------------------------------");
//替换陈六的成绩
class1.replace("陈六", "59分");
System.out.println("替换后陈六的成绩:" + class1.get("陈六"));
System.out.println("-------------------------------------");
//清空集合
class1.clear();
//判断集合是否为空
System.out.println("用clear方法清除后集合是否为空:" + class1.isEmpty());
}
}

总结:

Map以键值对的结构存储;
key出现重复时,新加入的key不会覆盖原key,但新加入的value会覆盖原key对应的value
key和value都可以使用null

特殊说明:其实Set集合就是将元素存储到Map的键上。创建HashSet对象A时,会底层会创建一个HashMap的对象map,当想Set集合A中添加元素时(A.add("abc")),此时会调用map.put("abc", obj);
所以Set的实现方式就是Map中key的实现方式(数组 + 单项链表),由于元素存储数组的下标由特定的hash算法获得,所以也称为散列存储
以下是HashSet中的源码//创建HashSet对象是会在底层创建一个HashMap对象
public HashSet() {
map = new HashMap<>();
}
//向Set集合中添加元素时,底层是将添加的元素添加到map集合的key上
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

TreeMap类

由名称可知,其key和TreeSet一样;其他属性同HashMap。所以这里不再详细讲述。
实例:package map.treeMap;
import java.util.Set;
import java.util.TreeMap;
/**
* 演示TreeSet集合
* @author 学霸联盟 - 赵灿
*/
public class TreeMapDemo {
public static void main(String[] args) {
//创建三个树枝对象
Branch b1 = new Branch(10);
Branch b2 = new Branch(5);
Branch b3 = new Branch(8);
//创建TreeMap对象
TreeMap tm = new TreeMap();
tm.put(b1, "树枝10");
tm.put(b2, "树枝5");
tm.put(b3, "树枝8");
//获取TreeMap中包含所有的key的集合
Set ts = tm.keySet();
//循环输出key
for(Object o : ts){
Branch b = (Branch)o;
//输出年轮
System.out.print("年轮:" + b.getAnnualRing());
//根据有序的key,获取有序的value
System.out.println(" 对应的value:" + tm.get(b));
}
}
}

/**
* 树枝类Branch
* 加入TreeSet集合的元素类型必须实现Comparable接口
* 否则程序运行的时候会出现异常
* @author 学霸联盟 - 赵灿
*/
class Branch implements Comparable{
//年轮:用于排序的依据
private int annualRing;
//带参构造方法
public Branch(int annualRing){
this.annualRing = annualRing;
}
//重写接口中的方法
@Override
public int compareTo(Object o) {
//强制类型转换
Branch b = (Branch)o;
/*
* 使用年轮作为排序比较的依据
* 当前对象年轮减去参数传入的Branch对象的年龄
* 结果等于0表示:两个树枝年轮相等,排序不分先后
* 结果大于0表示:当前对象的年轮大,排在后面
* 结果小于0表示:参数对象的年轮大,排在后面
*/
int result = this.annualRing - b.annualRing;
return result;
}
//获取年轮
public int getAnnualRing(){
return annualRing;
}
}
运行结果
年轮:5 对应的value:树枝5
年轮:8 对应的value:树枝8
年轮:10 对应的value:树枝10

Properties类

从文件中获取键值对
文件内容格式
key = value
实例:文件名:properties.txt
文件内容:
username = admin
password = 123456
文件地址:src/map/properties/properties.txt
其中文件地址是从项目根目录开始的
实例:
package map.properties;
import java.io.FileInputStream;
import java.util.Properties;
/**
* 演示Properties类中的一些常用方法
* @author 学霸联盟 - 赵灿
*/
public class PropertiesDemo {
public static void main(String[] args) {
//创建Properties对象
Properties p = new Properties();
/*
* 以下代码暂时先知道是什么作用即可,后面会讲解
* try - catch语句的作用是捕获异常
* load方法的作用是加载文件
* 其中的参数是文件的地址
*/
try {
p.load(new FileInputStream("src/map/properties/properties.txt"));
} catch (Exception e) {
System.out.println("加载出错");
}
//获取文件中username对应的值
String username = p.getProperty("username");
System.out.println("用户名:" + username);
//获取文件中password对应的值
String password = p.getProperty("password");
System.out.println("密码:" + password);
}
}
运行结果:
用户名:admin
密码:123456