双例集合
一、Map接口
1.Map接口的特点
2.Map与Collection的区别
3.Map接口的常用方法
其他的方法可自行通过api文档查询
二、HashMap容器类
/**
* 测试HashMap的相关方法
*/
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMap_Test {
public static void main(String[] args) {
//实例化HashMap容器
Map<String, String> m1=new HashMap<>();
System.out.println("--------添加元素----------");
//添加元素
/**在put方法中,如果Map中不存在添加的key值,则返回NULL;
如果存在该key值,则原来的value值被新的value值替换,且返回原来的value值
*/
System.out.println(m1.put("a", "A"));//输出null
System.out.println(m1.put("a", "A1"));//输出A,且在HashMap中原来的A被A1代替
m1.put("b", "B");//返回null
m1.put("c", "C");
m1.put("d", "D");
System.out.println("----------获取元素--------------");
//通过key值获取元素(value)
System.out.println(m1.get("a"));//需在知道key的情况下才能获取对应的value值,获取所有value值时不方便
System.out.println("------------------------");
//获取HashMap中所有元素可以通过keySet方法和get方法一起完成
Set<String> keys=m1.keySet();//获取所有的key存在Set容器中
for(String key:keys){
String value=m1.get(key);
System.out.println(key+"-----"+value);
}
System.out.println("------------------------");
//通过entrySet方法获取Map.Entry类型获取元素
//Map容器内有个Entry接口
Set<Map.Entry<String, String>> entrySet = m1.entrySet();
for(Map.Entry<String, String> entry:entrySet){
System.out.println("key:"+entry.getKey()+"---------"+"value:"+entry.getValue());
}
System.out.println("------------并集操作---------------");
Map<String, String> m2=new HashMap<>();
m2.put("e", "E");
m2.put("d", "D");
m2.put("b", "B1");
//并集时有相同的key值,m1(被并集操作的map容器)中的value值会把m2(当前的map容器)的value值给覆盖掉
m2.putAll(m1);
Set<String> key2=m2.keySet();
for(String key:key2){
System.out.println("key="+key+"-----------"+"value="+m2.get(key));
}
System.out.println("-----------删除元素-------------");
System.out.println(m2.remove("a"));//返回被删除元素的value值
Set<String> key3=m2.keySet();
for(String key:key3){
System.out.println("key "+key+" value "+m2.get(key));
}
System.out.println("---判断key与value是否存在-----");
System.out.println(m1.containsKey("a"));
System.out.println(m2.containsKey("a"));
System.out.println(m1.containsValue("A1"));
System.out.println(m2.containsValue("A1"));
}
}
三、HashMap的底层源码分析
1.底层存储介绍
2.HashMap的成员变量
DEFAULT_INITIAL_CAPACITY:默认数组部分的初始容量16,必须是2的次幂
MAXIMUM_CAPACITY:数组部分的最大容量2的30次方
DEFAULT_LOAD_FACTOR:负载因子,数组扩容的负载因子,当数组容量达到75%的时候(即16*0.75=12),开始扩容
TREEIFY_THRESHOLD : 当树的容量达到8时,转化为红黑树,链表转红黑树的一个阈值
UNTREEIFY_THRESHOLD : 红黑树转链表的一个阈值
MIN_TREEIFY_CAPACITY:当数组容量达到64时才进行链表与红黑树的转化
size:记录Map中的键值对的数量
table:存放链表和红黑树的数组
3.HashMap中存储元素的结点类型
链表的结点类Node
红黑树的结点类TreeNode
TreeNode类继承了Node类,以便于在table(Node类型的数组)中存放链表结点和红黑树结点
4.数组初始化
5.计算Hash值
- 获得key对象的hashcode,首先调用key 对象的hashcode()方法,获得key 的 hashcode值。
- 根据hashcode计算出hash值(要求在[0,数组长度-1]区间)hashcode是一个整数,我们需要将它转化成[O,数组长度-1]的范围。我们要 求转化后的hash 值尽量均匀地分布在[0,数组长度-1]这个区间,减少"hash冲突"
Hash方法:高16位于低16位的异或运算
6.添加元素
7.数组扩容
四、TreeMap容器类
TreeMap中添加元素时必须对key实现比较规则,否则会报错,TreeMap无法将一个没有比较规则的key添加进来
- 元素自身实现比较规则
- 通过比较器实现比较规则
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMap_Test {
public static void main(String[] args) {
//实例化TreeMap
System.out.println("------通过元素自身实现比较规则------");
Map<Users, String> map=new TreeMap<>();
Users u1=new Users("the Mutents", 21);
Users u2=new Users("小白", 20);
Users u3=new Users("李明", 20);
map.put(u1, "男");
map.put(u2, "女");
map.put(u3, "男");
Set<Users> keys=map.keySet();
for(Users key:keys){
System.out.println("key: "+key+" value: "+map.get(key));
}
System.out.println("-------通过比较器实现比较规则--------");
Map<Student, String> map2=new TreeMap<>(new StudentComparator());
Student s1=new Student("the Mutents", 21);
Student s2=new Student("小白", 20);
Student s3=new Student("李华", 20);
map2.put(s1, "男");
map2.put(s2, "女");
map2.put(s3, "男");
Set<Student> stu=map2.keySet();
for(Student key:stu){
System.out.println("key: "+key+" value: "+map2.get(key));
}
}
}
public class Users implements Comparable<Users>{
private String username;
private int userage;
public Users() {
super();
// TODO Auto-generated constructor stub
}
public Users(String username, int userage) {
super();
this.username = username;
this.userage = userage;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
@Override
public String toString() {
return "Users [username=" + username + ", userage=" + userage + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + userage;
result = prime * result + ((username == null) ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Users other = (Users) obj;
if (userage != other.userage)
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
//定义比较规则
//返回值为正数:大,返回值为负数:小,返回值为0:相等
//定义一个按年龄比较的比较规则,由小到大
@Override
public int compareTo(Users o) {
if(this.userage>o.getUserage()){
return 1;
}
if(this.userage==o.getUserage()){
return this.username.compareTo(o.getUsername());
}
return -1;
}
}
//比较器
import java.util.Comparator;
public class StudentComparator implements Comparator<Student> {
//定义比较规则
@Override
public int compare(Student o1, Student o2) {
if(o1.getAge()>o2.getAge()){
return 1;
}
if(o1.getAge()==o2.getAge()){
return o1.getName().compareTo(o2.getName());
}
return -1;
}
}