Map集合
- 用于存储任意键值对(Key-Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
Map父接口
- **特点:****存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复;将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
- 主要方法:
- V put(K key, V value) //将对象存入到集合中,关联键值。key重复则覆盖原值。
- Object get(Object key) //根据键获取对应的值
- Set //返回所有key
- Collection values() //返回包含所有值的Collection集合
- Set<Map.Entry<K, V> //键值匹配的Set集合
- containsKey //如果此映射包含指定键的映射关系,则返回true
- entrySet() //返回此映射中包含的映射关系的Set视图(效率高于keySet())
- keySet() //返回此映射中包含的键的Set视图
Map集合的实现类
HashMap
- JDK1.2版本,线程不安全,运行效率快;允许使用null作为key或value。
- 构造方法:HashMap() :构造一个具有默认初始容量(16)和默认加载因子(0.75)的空HashMap。
参考代码
import java.util.HashMap;
import java.util.Map;
//HashMap集合的使用
//存储结构:哈希表(数组 + 链表 + 红黑树(JDK1.8之后))
public class Demo02 {
public static void main(String[] args) {
//创建集合
HashMap<Student, String> stuhashMap = new HashMap<Student, String>();
//刚创建hashMap之后没有添加元素:table=null size=0;目的节省空间 在添加第一个元素后table容量调整为16
//添加元素
Student student1 = new Student("猴子",100);
Student student2 = new Student("八戒",80);
Student student3 = new Student("沙和尚",60);
stuhashMap.put(student1,"花果山");
//stuhashMap.put(student2,"高老庄");
stuhashMap.put(student3,"流沙河");
//stuhashMap.put(student1, "养马"); //key值重复元素个数不加,value值覆盖
stuhashMap.put(student2,"流沙河"); //值可以重复需要把(student2,"高老庄")注释
stuhashMap.put(new Student("猴子",100), "花果山"); //新建成功加入重复元素 但在Student类中重写hashcode和equals后无法新建重复元素
System.out.println("元素个数:" + stuhashMap.size());
System.out.println(stuhashMap.toString());
//删除
stuhashMap.remove(student2);
System.out.println("删除之后:" + stuhashMap.size());
System.out.println(stuhashMap.toString());
//遍历
System.out.println("------keySet------");
for (Student key : stuhashMap.keySet()) {
System.out.println(key.toString() + "------" + stuhashMap.get(key));
}
System.out.println("------entrySet------");
for (Map.Entry<Student, String> entry : stuhashMap.entrySet()) {
System.out.println(entry.getKey() + "------" + entry.getValue());
}
//判断
System.out.println(stuhashMap.containsKey(student1));
System.out.println(stuhashMap.containsValue("花果山"));
}
}
Student类
import java.util.Objects;
public class Student {
private String stuName;
private int stuID;
public Student() {
}
public Student(String stuName, int stuID) {
this.stuName = stuName;
this.stuID = stuID;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getStuID() {
return stuID;
}
public void setStuID(int stuID) {
this.stuID = stuID;
}
//重写equals()和hashCode()方法 不让元素重复
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuID == student.stuID &&
Objects.equals(stuName, student.stuName);
}
@Override
public int hashCode() {
return Objects.hash(stuName, stuID);
}
@Override
public String toString() {
return "Student{" +
"stuName='" + stuName + '\'' +
", stuID=" + stuID +
'}';
}
}
源码分析
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //hashMap初始容量大小 16
static final int MAXIMUM_CAPACITY = 1 << 30; //hashmap的数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75F; //默认加载因子
static final int TREEIFY_THRESHOLD = 8; //jdk1.8 当链表长度大于8时,调整为红黑数
static final int UNTREEIFY_THRESHOLD = 6; //jdk1.8 当链表长度小于6时,调整为链表
static final int MIN_TREEIFY_CAPACITY = 64; //jdk1.8 当链表长度大于8时,并且集合元素个数大于等于64时,调整为红黑数
transient Node<K,V>[] table; //哈希表中的数组
size; //元素个数
总结
- HashMap刚创建时,table是null,为了节省空间;当添加第一个元素后,table容量调整为16
- 当元素个数大于阈值(16(数组长度) * 0.75 = 12)时,会进行扩容,扩容后大小为原来的2倍,目的是减少调整元素的个数。
- JDK1.8 当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树,目的提高执行效率。
- JDK1.8 当链表长度小于6时,调整成链表。
- JDK1.8以前 链表是头插入,JDK1.8以后是尾插入
TreeMap集合(红黑树)
-
红黑数:左节点小于右节点
-
实现了SortedMap接口(是Map的子接口),可以对key自动排序。
参考代码
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
//TreeMap的使用
//存储结构:红黑树
public class Demo03 {
public static void main(String[] args) {
//新建集合
TreeMap<Student, String> treeMap = new TreeMap<Student, String>();
/* //定制比较
TreeMap<Student, String> treeMap = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return 0;
}
});
*/
//添加元素
Student student1 = new Student("猴子",100);
Student student2 = new Student("八戒",80);
Student student3 = new Student("沙和尚",60);
//需要在Student类中实现Comparable接口
treeMap.put(student1, "北京");
treeMap.put(student2, "上海");
treeMap.put(student3, "深圳");
treeMap.put(new Student("沙和尚",60), "江苏"); //实现Comparable接口后不能添加重复元素,但Value值被覆盖
System.out.println("元素个数:" + treeMap.size());
System.out.println(treeMap.toString());
//删除
treeMap.remove(student2);
System.out.println("删除后:" + treeMap.size());
System.out.println(treeMap.toString());
//遍历
System.out.println("------keySet()------");
for (Student key : treeMap.keySet()) {
System.out.println(key + "------" + treeMap.get(key));
}
System.out.println("------entrySet()------");
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + "-----" + entry.getValue());
}
//判断
System.out.println(treeMap.containsKey(student2));
System.out.println(treeMap.containsValue("北京"));
}
}
Student类
import java.util.Objects;
public class Student implements Comparable<Student> {
private String stuName;
private int stuID;
public Student() {
}
public Student(String stuName, int stuID) {
this.stuName = stuName;
this.stuID = stuID;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getStuID() {
return stuID;
}
public void setStuID(int stuID) {
this.stuID = stuID;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuID == student.stuID &&
Objects.equals(stuName, student.stuName);
}
@Override
public int hashCode() {
return Objects.hash(stuName, stuID);
}
@Override
public String toString() {
return "Student{" +
"stuName='" + stuName + '\'' +
", stuID=" + stuID +
'}';
}
@Override
public int compareTo(Student o) {
int n1 = this.stuID - o.getStuID();
return n1;
}
}