1. Map 接口实现类的特点 [很实用] 530
注意:这里讲的是JDK8的Map接口特点Map java
1) Map与Collection并列存在。 用于保存具有映射关系的数据:Key-Value
2) Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3) Map中的key不允许重复,原因和HashSet一样,前面分析过源码.
4) Map中的value可以重复
5) Map的key可以为null, value也可以为null,注意key为null,只能有一个,value为null ,可以多个
6)常用String类作为Map的key
7) key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value
代码在com.stulzl.map_.包中
map_
package com.stulzl.map_;
import java.util.HashMap;
import java.util.Map;
//Map接口实现类的特点 530
@SuppressWarnings({"all"})
public class Map_ {
public static void main(String[] args) {
//使用实现类HashMap来讲解
//1) Map与Collection并列存在。 用于保存具有映射关系的数据:Key-Value(双列元素)
//2. Map 中的 key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中
Map map = new HashMap();
map.put("no1", "中国");//k-v
map.put("no2", "张无忌");//k-v
//3. Map 中的 key 不允许重复,原因和HashSet 一样,前面分析过源码.
map.put("no1", "张三丰");//当有相同的K是就等价于替换 map={no2=张无忌, no1=张三丰}
//4. Map 中的 value 可以重复
map.put("no3", "张三丰");
//5. Map 的key 可以为 null, value 也可以为null ,注意 key 为null,只能有一个
// ,value 为null 可以多个
map.put(null,null);
map.put(null,"jack");//这不就相当于第三条中的替换效果嘛
map.put("no4", null); //k-v
map.put("no5", null); //k-v
//6. 常用String类作为Map的 key,其实只要是Object子类都可以
map.put(1,"赵敏");//这个就是int类型的
map.put(new Object(), "金毛狮王");//k-v//甚至直接new一个Object类也可以
//7. key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value
// 通过get 方法,传入 key ,会返回对应的value
System.out.println(map.get("no2"));//张无忌
System.out.println("map="+map);
}
}
1.1Map存放数据key-value的底层 531
8) Map存放数据的key-value示意图,一对k-v是放在一个HashMap$Node中的, 因为Node实现了Entry 接口,有些书上也说一对k~v就是一个Entry(如图) [代码演示]
代码在com.stulzl.map_source.包中
map_source
package com.stulzl.map_source;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//分析Map存放数据的key-value底层 531 看视频
@SuppressWarnings({"all"})
public class Map_Source {
public static void main(String[] args) {
//8) Map存放数据的key-value示意图,一对k-v是放在一个HashMap$Node中的,
//因为Node实现了Entry 接口,有些书上也说一对k~v就是一个Entry [代码演示]
Map map = new HashMap();
map.put("no1", "韩顺平");//k-v
map.put("no2", "张无忌");//k-v
//map.put(new Car(), new Person());//k-v
//解读
//1. k-v 最后是 HashMap$Node node = newNode(hash, key, value, null)
//2. k-v 为了方便程序员的遍历,还会 创建 EntrySet 集合 ,该集合存放的元素的类型 Entry, 而一个Entry
// 对象就有k,v EntrySet> 即: transient Set> entrySet;
//3. entrySet 中, 定义的类型是 Map.Entry ,但是实际上存放的还是 HashMap$Node
// 这时因为 static class Node implements Map.Entry
//4. 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历, 因为 Map.Entry 提供了重要方法
// K getKey(); V getValue();
//Map集合调用entrySet()方法返回一个set集合编译类型为HashMap$EntrySet
// 但实际Set的运行类型还是Node需要强转为Entry类型才能调用Entry接口中的方法遍历
Set set = map.entrySet();
//System.out.println(set.getClass());//类型是HashMap$EntrySet
//遍历
for (Object obj :set) {//Object类型是几乎所有类型的父类包括Node
//System.out.println(obj.getClass());//类型是HashMap$Node
//为了从 HashMap$Node 取出k-v
//1. 先做一个向下转型
Map.Entry entry = (Map.Entry)obj;//向下转型
System.out.println(entry.getKey()+"-"+entry.getValue());
}
//演示直接使用keySet方法遍历set1集合中k
Set set1 = map.keySet();//将k单独放在一个set1集合中
System.out.println(set1);//[no2, no1]
System.out.println(set1.getClass());//class java.util.HashMap$KeySet
//演示直接使用values方法遍历values集合中V
Collection values = map.values();//将V单独放在一个values集合中
System.out.println(values);//[张无忌, 韩顺平]
System.out.println(values.getClass());//class java.util.HashMap$Values
//总结
// k,v是被Entry接口封装且指向的,而Entry又被放在EntrySet集合中即 EntrySet>
// 将Entry放在EntrySet集合中是为了方便管理
// EntrySet是一个集合,里面的元素是Entry类型,而一个Entry对象就是一对k,v
// 但实际k,v是Node结点类型,因为Node实现了 Entry接口,之所以将Node对象以Entry类型
// 存放到 entrySet 集合中就是为了方便我们的遍历,因为本身HashMap$Node没有遍历方法,但是Entry接口
// 中有getKey(),getValue方法可以直接遍历
//Map提供了一些常用方法,如keySet()、values()、entrySet()等方法。
//Map是java中的接口,Map.Entry是Map的一个内部接口,此接口为泛型,
//定义为Entry。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。
//entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
}
}
class Car {
}
class Person{
}
2. Map接口的常用方法 532
put:添加
remove:根据键删除映射关系
get:根据键获取值
size:获取元素个数
isEmpty:判断个数是否为0
clear:清除k-v
containsKey:查找键是否存在
代码在com.stulzl.map_method.包中
map_method
package com.stulzl.map_method;
import java.util.HashMap;
import java.util.Map;
//Map接口的常用方法 532
@SuppressWarnings({"all"})
public class Map_Method {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", new Book("", 100));//OK
map.put("邓超", "孙俪");//替换-> 一会分析源码
map.put("王宝强", "马蓉");//OK
map.put("宋喆", "马蓉");//OK
map.put("刘令博", null);//OK
map.put(null, "刘亦菲");//OK
map.put("鹿晗", "关晓彤");//OK
map.put("hsp", "hsp的老婆");
System.out.println("map="+map);
// remove:根据键删除映射关系
map.remove(null);
System.out.println("map="+map);
// get:根据键获取值
Object val = map.get("鹿晗");
System.out.println("val="+val);
// size:获取元素个数
System.out.println("k-v="+map.size());
// isEmpty:判断个数是否为0
System.out.println(map.isEmpty());//f
// clear:清除k-v
// map.clear();
// System.out.println("map="+map);
// containsKey:查找键是否存在
System.out.println(map.containsKey("hsp"));//t
}
}
class Book{
private String name;
private int num;
public Book(String name, int num) {
this.name = name;
this.num = num;
}
}
3. Map接口的遍历方法 533
3.1 ➢Map遍历方式案例演示
1) containsKey;查找键是否存在
2) keySet:获取所有的键
3) entrySet:获取所有关系k-v
4) values:获取所有的值
代码在com.stulzl.map_for.包中
map_for
package com.stulzl.map_for;
import java.util.*;
//Map遍历方式 533
@SuppressWarnings({"all"})
public class Map_For {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", "孙俪");
map.put("王宝强", "马蓉");
map.put("宋喆", "马蓉");
map.put("刘令博", null);
map.put(null, "刘亦菲");
map.put("鹿晗", "关晓彤");
//第一组: 先取出 所有的Key , 通过Key 取出对应的Value
Set keyset = map.keySet();
//(1)增强for
System.out.println("=====增强for=====");
for (Object key :keyset) {
System.out.println(key+"-"+map.get(key));
}
//(2)迭代器
System.out.println("=====迭代器======");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();//next()方法下移后位置的集合元素返回
System.out.println(key+"-"+map.get(key));
}
//第二组: 把所有的values取出
Collection values = map.values();
//增强for
System.out.println("=====增强for=====");
for (Object value :values) {
System.out.println(value);
}
//迭代器
System.out.println("=====迭代器======");
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object value = iterator1.next();
System.out.println(value);
}
//第三组: 通过EntrySet 来获取 k-v
Set entryset = map.entrySet();//将entry 转成 Map.Entry
System.out.println("======使用entrySet的增强for=====");
for (Object o :entryset) {
Map.Entry m = (Map.Entry)o;//向下转型为Map.Entry
System.out.println(m.getKey()+"-"+m.getValue());
}
//使用迭代器
System.out.println("======使用entrySet的迭代器=====");
Iterator iterator2 = entryset.iterator();
while (iterator2.hasNext()) {
Object next = iterator2.next();//HashMap$Node
//HashMap$Node -实现-> Map.Entry接口 (getKey,getValue)
Map.Entry m = (Map.Entry)next;//向下转型为Map.Entry
System.out.println(m.getKey()+"-"+m.getValue());
}
}
}
4. Map 接口课堂练习 534
使用HashMap添加3个员工对象,要求
键:员工id
值:员工对象
并遍历显示工资> 18000的员工(遍历方式最少两种)
员工类:姓名、工资、员工id
代码在com.stulzl.map_exercise01.包中
map_exercise01
package com.stulzl.map_exercise01;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
//Map 接口课堂练习 534
//使用HashMap添加3个员工对象,要求
//键:员工id
//值:员工对象
//并遍历显示工资> 18000的员工(遍历方式最少两种)
//员工类:姓名、工资、员工id
@SuppressWarnings({"all"})
public class Map_Exercise01 {
public static void main(String[] args) {
Map map = new HashMap();
map.put(123,new Employee("jack",18500,"123"));
map.put(456,new Employee("tom",19000,"456"));
map.put(789,new Employee("smith",16000,"789"));
//遍历 2 种方式
//并遍历显示工资>18000 的员工(遍历方式最少两种)
//1. 使用 keySet -> 增强 for
System.out.println("=====第一种遍历方式增强for=====");
Set keySet = map.keySet();//先取出 所有的Key , 通过Key 取出对应的Value
for (Object key :keySet) {
//先获取value map.get(key)的编译类型是Object 运行类型就是Employee
//因为你想要的是工资,而工资只有value包括,如果你要用key强转的话是得不到工资的,
// 因为key只是integer类型,并不是Employee类型的,
// 只有value是Employee类型才能符合强转并得到想要的结果
Employee employee = (Employee)map.get(key);//向下转型Object->Employee
if(employee.getSalary()>18000){
System.out.println(employee);
}
}
//2. 使用 EntrySet -> 迭代器
System.out.println("=====第二种遍历方式迭代器=====");
Set entryset = map.entrySet();
Iterator iterator = entryset.iterator();//调用迭代器
while (iterator.hasNext()) {
Object next = iterator.next();//将下一个集合元素(Node结点类型)返回
Map.Entry m = (Map.Entry)next;//将Node结点类型向下转型为Map.Entry
//通过entry 取得key 和 value m.getValue()就是得到value,编译类型为Object
Employee employee2 = (Employee)m.getValue();//将得到的v向下转型为Employee
if(employee2.getSalary()>18000){
System.out.println(employee2);
}
}
}
}
class Employee{
private String name;
private double salary;
private String id;
public Employee(String name, double salary, String id) {
this.name = name;
this.salary = salary;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", id='" + id + '\'' +
'}';
}
}
5. Map 接口实现类-HashMap 535
5.1 HashMap 小结
1) Map接口的常用实现类HashMap、 Hashtable和Properties.
2) HashMap是Map接口使用频率最高的实现类。
3) HashMap是以key-val对的方式来存储数据(HashMap$Node类型)
4) key不能重复,但是值可以重复,允许使用null键和null值。
5)如果添加相同的key,则会覆盖原来的key-val ,等同于修改.(key不会替换,val会替换)
6)与HashSet-样,不保证映射的顺序,因为底层是以hash表的方式来存储的. jdk8的
hashMap底层数组+链表+红黑树)
7) HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有
synchronized