8-Map接口和常用方法
8-Map接口和常用方法
- Map 与 Collection 并列存在。用于保存具有映射关系的数据:Key-Value
- Map 中的 key 和 value 可以是任何引用数据类型,会封装到 HashMap$Node 对象中
- Map 中的 key 不允许重复
- Map 中的 value 可以重复
- Map 的 key 可以为 null ,value 也可以为 null ,注意 key 为 null,只能有一个,value 为 null ,可以多个。
- 常用 String 类作为 Map 的 key
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value
- 遍历存储的 Key-Value 数据结点,是通过视图(EntrySet、Values、KeySet)间接获取的,请看如下示意图
注意:遍历存储的数据,本质上通过调用 HashIterator 迭代器进行的,并且 KeySet、Values、EntrySet 对象中并不存放存储的数据。还有就是 HashMap$Node 继承 Map.Entry<K,V> ,这一点要注意。还有就是一定要注意 EntrySet 集合,是通过 entrySet 方法初始化的。还有 HashMap 中的 toString (继承父类)会调用 entrySet . iterator 方法进行获取存储的数据,这也是为啥在 IDEA 中 Debug 中,发现并未调用 entrySet 方法就会发现 EntrySet 集合会被初始化了,并且初始化了其中还包括数据,这是因为 IDEA 中 Debug 过程会调用 HashMap 中的 toString 方法,进行获取其中内容,所以 EntrySet 集合会被初始化及赋值
- 查看 EntrySet 集合初始化及获取数据过程测试
package map;
import java.lang.reflect.Field;
import java.util.HashMap;
public class MapEntrySet {
@SuppressWarnings({"all"})
public static void main(String[] args) {
HashMap hashMap = new HashMap();
Field entrySetField = null ;
try {
// 通过反射机制获取 HashMap 中的 entry 属性成员(Set<Map.Entry<K,V>> 类型)
entrySetField = HashMap.class.getDeclaredField("entrySet");
// 开启 entry 属性成员的访问权限
entrySetField.setAccessible(true);
// 从 HashMap 对象中获取 entry 属性成员
Object entrySet = entrySetField.get(hashMap);
// 打印该属性成员,查看属性成员是否为空
System.out.println("entrySet=" + entrySet);
// 模拟 IDEA 的 Debug 过程中调用 toString 方法获取数据(检验 entrySet 属性是否被初始化)
System.out.println("hashMap.toString" + hashMap.toString());
// 从 HashMap 对象中获取 entry 属性成员
entrySet = entrySetField.get(hashMap);
// 打印该属性成员,查看属性成员是否为空
System.out.println("entrySet=" + entrySet);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
- 遍历 HashMap 中的数据
package map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapExercise {
@SuppressWarnings({"all"})
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put(1,new Employee02("吴彦祖",20000,1)) ;
hashMap.put(2,new Employee02("彭于晏",15000,2)) ;
hashMap.put(3,new Employee02("杨洋",28000,3)) ;
// Set<Map.Entry<K,V>> 遍历
Set entrySet = hashMap.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
Employee02 entryValue = (Employee02) entry.getValue();
if (entryValue.getSalary() > 18000) {
System.out.println("====工资大于 18000 的员工信息为" + entryValue);
}
}
// keySet 遍历
Set keySet = hashMap.keySet();
for (Object object : keySet) {
Employee02 employee02 = (Employee02) hashMap.get(object);
if (employee02.getSalary() >18000) {
System.out.println("====工资大于 18000 的员工信息为" + employee02);
}
}
}
}
@SuppressWarnings({"all"})
class Employee02 {
private String name ;
private double salary ;
private int id ;
@Override
public String toString() {
return "Employee02{" +
"name='" + name + '\'' +
", salary=" + salary +
", id=" + id +
'}';
}
public Employee02(String name, double salary, int 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 int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
- 总结
- Map 接口的常用实现类:HashMap、Hashtable 和 Properties。
- HashMap 是 Map 接口使用频率最高的实现类。
- HashMap 中存储数据是以 key 的 hash 值来获取表中存储的索引位置,进行存储。
- 若添加相同的 key,则会覆盖原来的 key-value 数据节点中的 value 值。(在 putval 方法中的一个参数 onlyIfAbsent 控制当相同的 key 时,是否要覆盖)
- 与 HashSet 一样,HashMap 的映射顺序也是无序的。
- HashMap 没有实现线程同步,若使用须考虑多线程场景。