1.Map概述
Map被称为双列集合,典型的key,value结构,Map集合有如下特点:
1.Map集合的键和值都可以为空,但在同一个集合中键为null的只能有一个,值为null的可以有多个
2.Map集合具有一对一的映射关系,即可以由相应的键得到相应的值
3.Map集合中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
4.Map中的key不允许重复,value可以重复
5.常用String类作为Map集合的Key
6.因为每对key,value都是存放在Node节点中的,又因为Node实现了Entry接口,故每对key,value又可以说是一个Entry,每个Entry放在EntrySet中,就组成了EntrySet集合,如下图所示:
2.Map接口方法
2.1 size()方法
2.2 isEmpty()方法
2.3 containsKey(Object key)
2.4 containsValues(Object value)
2.5 put(Object key,Object value)
2.6 remove(Object key)
2.7 putAll(Map<? extends Object,? extends Object >)
2.8 clear()
2.9 keySet()
2.10 values()
2.11 entrySet()
2.12 get(Object key)
3.Map六大遍历方式
package com.company.hashmap;
import javafx.beans.binding.ObjectExpression;
import java.util.*;
public class HashMapDemo2 {
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put(1,new Employee("张三",18000.0,1));
hashMap.put(2,new Employee("张三",18100.0,2));
hashMap.put(3,new Employee("张三",18101.0,3));
Collection values = hashMap.values();
// 增强for循环遍历value
System.out.println("增强for循环遍历value");
for(Object employee : values){
Employee employee1 = (Employee)employee;
Double salary = employee1.getSalary();
if(salary > 18000){
System.out.println(employee1);
}
}
// 迭代器遍历values
System.out.println("迭代器遍历values");
Iterator iterator = values.iterator();
while (iterator.hasNext()){
Employee next = (Employee)iterator.next();
Double salary = next.getSalary();
if(salary > 18000){
System.out.println(next);
}
}
// 增强for循环遍历key
System.out.println("增强for循环遍历key");
Set set = hashMap.keySet();
for(Object employee : set){
Integer key = (Integer) employee;
Employee employee1 = (Employee) hashMap.get(key);
Double salary = employee1.getSalary();
if(salary > 18000){
System.out.println(employee1);
}
}
// 迭代器遍历key
System.out.println("迭代器遍历key");
Iterator iterator1 = set.iterator();
while (iterator1.hasNext()){
Object next = iterator1.next();
Employee employee = (Employee) hashMap.get(next);
if(employee != null && employee.getSalary() > 18000.0){
System.out.println(employee);
}
}
// 增强for循环遍历entrySet
System.out.println("增强for循环遍历entrySet");
Set set1 = hashMap.entrySet();
for(Object entry : set1){
Map.Entry entry1 = (Map.Entry)entry;
Employee employee = (Employee) entry1.getValue();
if(employee != null && employee.getSalary() > 18000.0){
System.out.println(employee);
}
}
// 迭代器遍历entrySet
System.out.println("迭代器遍历entrySet");
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()){
Map.Entry entry = (Map.Entry)iterator2.next();
Employee employee = (Employee) entry.getValue();
if(employee != null && employee.getSalary() > 18000.0){
System.out.println(employee);
}
}
}
}
class Employee{
private String name;
private Double salary;
private int id;
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Employee() {
}
public Employee(String name, Double salary, int id) {
this.name = name;
this.salary = salary;
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return id == employee.id &&
Objects.equals(name, employee.name) &&
Objects.equals(salary, employee.salary);
}
@Override
public int hashCode() {
return Objects.hash(name, salary, id);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", id=" + id +
'}';
}
}
4.Map的实现类
4.1HashMap
- HashMap是Map接口使用频率最高的实现类
- HashMap是以键值对的形式来存储数据
- key不能重复,value可以重复,允许使用null键和null值
- 如果添加相同的key则会覆盖原来的key-value(相当于key不变,value更新为最新的值)
- 与HashSet一样不能保证映射的顺序,因为底层是以hash表的方式来存储的
- HashMap没有实现线程同步,因此线程不安全
4.1.1HashMap底层实现原理简述
1.当往HashMap集合中添加第一个元素时,调用key的hashcode方法计算出hash值,然后通过某种算法得出在table数组的索引位置
2.如果该位置没有元素,则直接添加
3.如果该位置有元素则调用key的equals方法,如果返回true,则覆盖掉相同key的value。如果返回false,则将要添加的元素链接在该元素的的后面
4.1.2 HashMap底层扩容机制(无参构造器并且针对的是jdk1.8)
1.先初始化一个空的table,当往该table中添加第一个元素时,该数组扩容为16,加载因子为0.75,临界值为12
2.当table中的元素个数超过12时,以2倍当前容量进行扩容,即扩为32,加载因子为0.75,临界值为24(后续添加元素以此类推,注意table数组不会无限扩容,有一个上限)
3.当table数组大小>=64且链表大小>=8时,该链表会转化成红黑树
4.1.3 HashMap实现类之LinkedHashMap
LinkedHashMap相较于HashMap在查询方面效率更高,因为其底层实现了双向链表。
4.2TreeMap
TreeMap在使用过程中需要用到自然排序和定制排序,在用到自然排序时,key所在的类要实现comparatable接口,在使用定制排序时,TreeMap构造器中要传入匿名内部类对象
4.2.1自然排序
TreeMap treeMap1 = new TreeMap();
treeMap1.put(new Employee(1,"jack"),1);
treeMap1.put(new Employee(1,"lucy"),2);
treeMap1.put(new Employee(5,"jerry"),3);
System.out.println(treeMap1);
class Employee implements Comparable{
private int age;
private String name;
public Employee() {
}
public Employee(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public String toString() {
return "Employee{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Object o) {
if(o instanceof Employee){
Employee employee = (Employee)o;
// 按照年龄来排序
int compare = Integer.compare(this.age, employee.age);
// 如果年龄相同,按照姓名来排序
if(compare == 0){
return this.name.compareTo(employee.name);
}
return compare;
}
return 0;
}
}
4.2.2 定制排序
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
treeMap.put("no1","黄劭鸿");
treeMap.put("no2","黄劭鸿");
treeMap.put("no3","黄劭鸿");
treeMap.put("no4","黄劭鸿");
treeMap.put("no5","黄劭鸿");
treeMap.put("no6","黄劭鸿");
treeMap.put("no7","黄劭鸿");
注意:无论是定制排序还是自然排序,当比较结果返回零时,该元素不会加入到TreeMap集合中,理由如下:
4.3Hashtable
1.Hashtable的键值都不能为null,如果为null则会报空指针异常
2.Hashtable是线程安全的
4.3.1 Hashtable底层实现原理简述
1.当往Hashtable集合中添加第一个元素时,调用key的hashcode方法计算出hash值,然后通过某种算法得出在table数组的索引位置
2.如果该位置没有元素,则直接添加
3.如果该位置有元素则调用key的equals方法,如果返回true,则覆盖掉相同key的value。如果返回false,则将要添加的元素链接在该元素的的后面(注意Hashtanle的数据结构为数组+链表),链表不会转化成红黑树
4.3.2 Hashtable底层扩容机制
1.table数组初始为空,当往Hashtable集合中添加第一个元素时,table数组扩容为11,加载因子为0.75,临界值为8
2.当table数组中的个数超过8的时候,以2倍原数组+1的原则扩容,即扩为23,加载因子为0.75,临界值为17(后面的扩容以此类推,同样table数组不能无限扩容)
4.3.3 Hashtable实现类之Properties
Properties与配置文件相关,可以给它的对象发送消息,来读取配置文件中的相关内容。
package com.atguigu.java;
import org.junit.Test;
import java.io.FileInputStream;
import java.util.Properties;
public class PropertiesTest {
@Test
public void testProperties() throws Exception{
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
properties.load(fileInputStream);
String name = properties.getProperty("name");
String password = properties.getProperty("password");
System.out.println("name:"+name+",password:"+password);
}
}