Map
接口 和 常用方法
Map
接口实现类的特点
注意:这里讲的是jdk8
的Map
接口特点【必须掌握背下】
-
Map
与Collection
并列存在。用于保存具有映射关系的数据:Key_Valeu
双列元素 -
Map
中的Key
和Value
可以是任何引用类型的数据,会封装到HashMap$Node
对象中 -
Map
中的key
不允许重复,原因和HashSet
一样,当有相同的Key
时,会替换掉原来的key-value
-
Map
中的Value
可以重复 -
Map
的key
可以为null
,value
也可以为null
,注意key
为null
只能有一个,value
为null
可以有多个 -
常用
String
类作为Map
的key
-
key
和value
之间存在单向一对一关系,即通过指定的key
总能找到对应的value
-
Map
存放数据的key-value
示意图,一对k-v
是放在一个HashMap$Node
中的,有因为Node
实现了Entry
接口,也就说一对k-v
就是一个Entry
第八点的理解是:
1.每个
k-v
最后是存放在HashMap$Node = newNode(hash,key,value,null)
中2.要因为方便程序员的的遍历,还创建了
EntrySet
集合,该集合存放的元素是Entry
,而一个Entry
对象就有k,v EntrySet<EntrySet<Entry<K,V>>
即:transient Set<Map.Entry<K,V>> entrySet;
3.
entrySet
中, 定义的类型是Map.Entry
,但是实际上存放的还是HashMap$Node
这时因为static class Node<K,V> implements Map.Entry<K,V>
【其实是多态数组】4.当把
HashMap$Node
对象 存放到entrySet
就方便我们的遍历, 因为Map.Entry
提供了重要方法K getKey(); V getValue();
存储的顺序和取出的顺序是不一致的,本质底层是HashMap
package com.hspedu.map_;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"all"})
public class MapSource_ {
public static void main(String[] args) {
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<Entry<K,V>> 即: transient Set<Map.Entry<K,V>> entrySet;
//3. entrySet 中, 定义的类型是 Map.Entry ,但是实际上存放的还是 HashMap$Node
// 这时因为 static class Node<K,V> implements Map.Entry<K,V>
//4. 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历, 因为 Map.Entry 提供了重要方法
// K getKey(); V getValue();
Set set = map.entrySet();
System.out.println(set.getClass());// HashMap$EntrySet
for (Object obj : set) {
//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() );
}
Set set1 = map.keySet();
System.out.println(set1.getClass());
Collection values = map.values();
System.out.println(values.getClass());
}
}
class Car {
}
class Person{
}
Map
接口常用方法
Map接口常用方法
1. put:添加
2. remove:根据键删除映射关系
3. get:根据键获取值
4. size:获取元素个数
5. isEmpty:判断个数是否为0
6. clear:清除集合中所有元素
7. containsKey:查找键是否存在
Modifier and Type | Method and Description |
---|---|
void | clear() 从该地图中删除所有的映射(可选操作)。 |
boolean | ``containsKey(Object key)如果此映射包含指定键的映射,则返回 true` 。 |
boolean | containsValue(Object value) 如果此地图将一个或多个键映射到指定的值,则返回 true 。 |
Set<Map.Entry<K,V>>** ** | entrySet() 返回此地图中包含的映射的Set 视图。 |
boolean | equals(Object o) 将指定的对象与此映射进行比较以获得相等性。 |
default void | forEach(BiConsumer<? super K,? super V> action) 对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。 |
V | get(Object key) 返回到指定键所映射的值,或 null 如果此映射包含该键的映射。 |
default V | getOrDefault(Object key, V defaultValue) 返回到指定键所映射的值,或 defaultValue 如果此映射包含该键的映射。 |
int | hashCode() 返回此地图的哈希码值。 |
boolean | isEmpty() 如果此地图不包含键值映射,则返回 true 。 |
Set<K> | keySet() 返回此地图中包含的键的Set 视图。 |
V | put(K key, V value) 将指定的值与该映射中的指定键相关联(可选操作)。 |
void | putAll(Map<? extends K,? extends V> m) 将指定地图的所有映射复制到此映射(可选操作)。 |
V | remove(Object key) 如果存在(从可选的操作),从该地图中删除一个键的映射。 |
default boolean | remove(Object key, Object value) 仅当指定的密钥当前映射到指定的值时删除该条目。 |
default V | replace(K key, V value) 只有当目标映射到某个值时,才能替换指定键的条目。 |
default boolean | replace(K key, V oldValue, V newValue) 仅当当前映射到指定的值时,才能替换指定键的条目。 |
default void | replaceAll(BiFunction<? super K,? super V,? extends V> function) 将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常。 |
int | size() 返回此地图中键值映射的数量。 |
Collection<V> | values() 返回此地图中包含的值的Collection 视图。 |
package collection_.collectionP.map_;
import java.util.HashMap;
import java.util.Map;
/**
* @author: 海康
* @version: 1.0
*/
public class Map01 {
public static void main(String[] args) {
Map map = new HashMap();
// put 添加方法
map.put(101,"海康");
map.put(101,"西安"); // 注意是:当key值一样时,相当于替换了原来的 v
map.put(102,"湛江");
map.put(null,"广州");
map.put(103,"杭州");
map.put(104,"深圳");
System.out.println(map);
// remove 根据键删除映射关系
Object remove = map.remove(null);
System.out.println(remove);
// get 根据键获取值
Object o = map.get(101);
System.out.println(o);
// size 获取元素个数
System.out.println(map.size());
// isEmpty 判断个数是否为 0
System.out.println(map.isEmpty());
// clear 清除集合中所有元素
map.clear();
// containsKsy 查找键是否存在
System.out.println(map.containsKey(102));
}
}
Map
接口的遍历方法
由于元素的k-v
是存在在HashMap$Node
的内部类中,又因为HashMap$Node
内部实现了Map.Entry
接口,可以将HashMap$Node
存放在Map.Entry
中【其实是多态数组的方式】
Map
接口遍历方式是围着keySet
和values
和Entry
遍历的
遍历方法:
1. keySet:获取所有的键
2. entrySet:获取所有关系的 k-v
3. values:获取所有的值
4. containsKey:查找键是否存在
// 方式一:根据键遍历
// 方式二:根据值遍历
// 方式三:根据entrySet
遍历
三种方式都对应的上图
package collection_.collectionP.map_;
import java.util.*;
/**
* @author: 海康
* @version: 1.0
*/
public class MapFor {
public static void main(String[] args) {
Map map = new HashMap();
// put 添加方法
map.put(101,"海康");
map.put(101,"西安"); // 注意是:当key值一样时,相当于替换了原来的 v
map.put(102,"湛江");
map.put(null,"广州");
map.put(103,"杭州");
map.put(104,"深圳");
// 方式一:根据获取键方式来遍历
System.out.println("----键方式中增加for----");
Set set = map.keySet();
// 由于返回是set 集合所以可以使用增加for循环 和 迭代器方式
// 1.1 增加for
for (Object obj :set) {
System.out.println(obj+"="+map.get(obj));
}
// 1.2 迭代器方式
System.out.println("----键方式中迭代器----");
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj+"-"+map.get(obj));
}
// 方式二:根据值来获取
Collection values = map.values();
// 由于根据值来获取返回是一个Collection集合,也有两种方式遍历
// 一种是增加for 另一种是迭代器
System.out.println("----根据值来获取中的增加for");
for (Object obj:
values) {
System.out.println(obj);
}
System.out.println("----根据值来获取中的迭代器");
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object obj = iterator1.next();
System.out.println(obj);
}
// 方式三:根据entrySet方式
Set entrySet = map.entrySet();
System.out.println("----根据entrySet方式中增加for");
// 由于返回是Set集合还是有增加for和迭代器的方式遍历
for (Object obj:
entrySet) {
// 由于要使用Map.Entry方法需要向下强转成Entry类
// 使用Entry内部类中getKey方法和getValue方法
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey()+"-"+entry.getValue());
}
System.out.println("----根据entrySet方式中增加for");
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Object obj = iterator2.next();
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey()+"-"+entry.getValue());
}
/**
* 返回值:
* ----键方式中增加for----
* null=广州
* 101=西安
* 102=湛江
* 103=杭州
* 104=深圳
* ----键方式中迭代器----
* null-广州
* 101-西安
* 102-湛江
* 103-杭州
* 104-深圳
* ----根据值来获取中的增加for
* 广州
* 西安
* 湛江
* 杭州
* 深圳
* ----根据值来获取中的迭代器
* 广州
* 西安
* 湛江
* 杭州
* 深圳
* ----根据entrySet方式中增加for
* null-广州
* 101-西安
* 102-湛江
* 103-杭州
* 104-深圳
* ----根据entrySet方式中增加for
* null-广州
* 101-西安
* 102-湛江
* 103-杭州
* 104-深圳
*/
}
}
课堂练习:
package collection_.collectionP.map_;
import java.util.*;
/**
* @author: 海康
* @version: 1.0
*/
public class MapExercise01 {
public static void main(String[] args) {
Map map = new HashMap();
map.put(101,new Employee(101,"海康",68881.88));
map.put(102,new Employee(102,"海康",68881.88));
map.put(102,new Employee(102,"湛江",68881.88));// 由于key与上面的语句一样,所以value值会被替换掉
map.put(103,new Employee(103,"南宁",6888.88));
map.put(103,new Employee(103,"西安",8888.88));
// System.out.println(map);
// 遍历方式:
// 方式一:使用key方式
// 使用Key值中迭代器方式
System.out.println("----使用Key值中迭代器方式----");
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
Employee employee = (Employee) map.get(obj);
if (employee.getSalary() > 18000)
System.out.println(obj+"-"+employee);
}
System.out.println("----使用Key值中增加for循环方式----");
for (Object obj:
set) {
Employee employee = (Employee) map.get(obj);
if (employee.getSalary() > 18000)
System.out.println(obj+"-"+employee);
}
// 使用entrySet方式
Set entrySet = map.entrySet();
// 使用entrySet中迭代器方式
System.out.println("----使用entrySet中迭代器方式----");
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()) {
Object obj = iterator1.next();
Map.Entry entry = (Map.Entry) obj;
Employee employee = (Employee) entry.getValue();
if (employee.getSalary() > 18000)
System.out.println(entry.getKey()+"-"+ employee);
}
System.out.println("----使用entrySet中增加for方式----");
for (Object obj :entrySet) {
Map.Entry entry = (Map.Entry)obj;
Employee employee = (Employee) entry.getValue();
if (employee.getSalary() > 18000)
System.out.println(entry.getKey()+"-"+employee);
}
/**
* 返回值:
* ----使用Key值中迭代器方式----
* 101-Employee{Id=101, name='海康', salary=68881.88}
* 102-Employee{Id=102, name='湛江', salary=68881.88}
* ----使用Key值中增加for循环方式----
* 101-Employee{Id=101, name='海康', salary=68881.88}
* 102-Employee{Id=102, name='湛江', salary=68881.88}
* ----使用entrySet中迭代器方式----
* 101-Employee{Id=101, name='海康', salary=68881.88}
* 102-Employee{Id=102, name='湛江', salary=68881.88}
* ----使用entrySet中增加for方式----
* 101-Employee{Id=101, name='海康', salary=68881.88}
* 102-Employee{Id=102, name='湛江', salary=68881.88}
*/
}
}
class Employee {
private Integer Id;
private String name;
private double salary;
public Employee() {
}
public Employee(Integer id, String name, double salary) {
Id = id;
this.name = name;
this.salary = salary;
}
public double getSalary() {
return salary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Double.compare(employee.salary, salary) == 0 && Objects.equals(Id, employee.Id) && Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(Id, name, salary);
}
@Override
public String toString() {
return "Employee{" +
"Id=" + Id +
", name='" + name + '\'' +
", salary=" + salary +
'}';
}
}
package com.hspedu.map_;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"all"})
public class MapExercise {
public static void main(String[] args) {
//完成代码
Map hashMap = new HashMap();
//添加对象
hashMap.put(1, new Emp("jack", 300000, 1));
hashMap.put(2, new Emp("tom", 21000, 2));
hashMap.put(3, new Emp("milan", 12000, 3));
//遍历2种方式
//并遍历显示工资>18000的员工(遍历方式最少两种)
//1. 使用keySet -> 增强for
Set keySet = hashMap.keySet();
System.out.println("====第一种遍历方式====");
for (Object key : keySet) {
//先获取value
Emp emp = (Emp) hashMap.get(key);
if(emp.getSal() >18000) {
System.out.println(emp);
}
}
//2. 使用EntrySet -> 迭代器
// 体现比较难的知识点
// 慢慢品,越品越有味道.
Set entrySet = hashMap.entrySet();
System.out.println("======迭代器======");
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry)iterator.next();
//通过entry 取得key 和 value
Emp emp = (Emp) entry.getValue();
if(emp.getSal() > 18000) {
System.out.println(emp);
}
}
}
}
/**
* 使用HashMap添加3个员工对象,要求
* 键:员工id
* 值:员工对象
*
* 并遍历显示工资>18000的员工(遍历方式最少两种)
* 员工类:姓名、工资、员工id
*/
class Emp {
private String name;
private double sal;
private int id;
public Emp(String name, double sal, int id) {
this.name = name;
this.sal = sal;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", sal=" + sal +
", id=" + id +
'}';
}
}
HashMap
小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6wxNtXd-1647523718467)(E:\Typora笔记\java笔记\img\image-20220221213341557.png)]
Map
接口常用实现类:HashMap
Hashtable
和Properties
HashMap
是Map
接口使用频率最高的实现类HashMap
是以key-value
对的方式来存储数据HashMap$Node类型
,为方便将其存放在entrySet
集合中key
不能重复,但是值可以重复,允许使用null
键和null
值- 如果添加相同的
key
,则会覆盖原来的key-value
上的value
值【就是value
被替换掉】 - 与
HashMap
一样,不保证映射的顺序,因为底层是以hash
表的方式来存储的【jdk8的hashMap底层是 数组+链表+红黑树
】 HashMap
没有实现同步,因为是线程不安全的,方法没有做同步互斥的操作,没有synchronized
关键字