Map
-
Map接口:内部存储的元素都是key–value组成的键值对,无序并且没有下标;通过key访问value,key不可重复
-
Map集合有 key 和value值,它们成对出现,成为对应的Entry 对象
-
key值 可以是任意类型,无序,不可重复,允许null值;用Set集合表示
-
value值 可以是任意类型,无序,可以重复,允许null值;用Collection集合表示
-
Map实现类
- HashMap:Key允许null不允许重复,无序,线程不安全(动态数组+链表/红黑树)
- TreeMap:Key不允许null不允许重复,无序,对键自动排序,要求作为键的对象必须实现Comparable接口(平衡二叉树)
怎么获取map集合中的key和value,有什么方式?
1、查找所有的key值: 调用keySet()方法
Map map = new HashMap();
Set keySet = map.keySet();
for(Object key : keySet){
System.out.println("key:"+key+",value:"+map.get(key));
}
2、查找所有的value值:调用values()方法
Map map = new HashMap();
Collection valueSet = map.Values();
for(Object value : valueSet){
System.out.println("value:"+map.get(key));
}
3、单个value值【根据key获取value值】: 调用get(key)方法。
4、 【1】查找所有的Entry值: 调用entrySet()方法;
【2】遍历该Entry集合,执行 getKey() 或 getValue()
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for(Entry<String,String> en : entrySet){
String key = en.getKey();
String value = en.getValue();
System.out.println(key+","+value);
}
问题:key不相等则新元素插入到旧元素的后面,next怎么指向
HashMap
- put往map里面存储元素(数组长度默认为16,负载因子0.75,即当长度为16*0.75=12时扩容,扩容两倍)
- 根据key值进行判断hash,得到key的int hash值
- hash & 数组长度->下标(用key的哈希值和数组长度做与运算,余数就是当前元素的下标)
- 将这个元素存放到对应的下标
- get获取map里面的元素
- 根据key值进行判断hash,得到key的int hash值
- hash & 数组长度->下标(用key的哈希值和数组长度做与运算,余数就是当前元素的下标)
- 根据下标获取数组里面的元素
- hash碰撞或者不同的hash值 与数组长度&运算:导致下标一样
- 当发现相同的下标已经存储了元素,就根据equals判断key值是否相等
- key相等则进行元素覆盖
- key不相等则新元素占据旧元素的位置,新元素里面next指向旧元素(单链表)(jdk1.7是这样占据旧的位置)
- key不相等则新元素插入到旧元素的后面,新元素里面next指向旧元素(单链表)
- 变形
- 添加元素:当链表长度超过8个元素,并且数组长度大于64,就将链表变形成红黑树进行存储
- 移除元素:当移除只剩6个元素时,红黑树会自动变成链表
- 当发现相同的下标已经存储了元素,就根据equals判断key值是否相等
基本用法
package com.qianfeng.xqc.day0306;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* map存储的 键值对,key value的存放方式
* 增:put(key,value);key不可重复 , value随便
* 删:map.remove("1001");//根据key值删除
* 查:get(key); //只能通过key值获取value值; 不能通过value值获取key
* 改 : 不存在修改key; 如果key不一样,就代表是新增
* @author 淳
*
*/
public class DemoHashMap {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
//增 put(key,value); key不可重复 , value随便
map.put("1001", "张三");
map.put("1002", "翠花");
map.put("9999", "rose");
map.put("6666", "jack");
map.put(null,"什么都没有");
System.out.println(map.size());
//删
// map.remove("1001");//根据key值删除
map.remove("rose"); //移除失败; 因为没有key值rose
System.out.println(map.size());
//改 : 不存在修改key; 如果key不一样,就代表是新增;
map.put("1001","李四"); //修改;将我们对应key里面的value进行修改;
//查
//1: 查一个 get(key); //只能通过key值获取value值; 不能通过value值获取key;
String name = map.get("1001"); //如果没有这个key值,将会返回null
System.out.println(name);
//2: 遍历
//2.1 获取所有的key值,通过key值去遍历
Set<String> set = map.keySet();
System.out.println(set.getClass());
//set: 存放的咱们map所有的key值;
for(String str : set) {
//str : 代表我们每一次取出来的key值.
//如何获取value值;
System.out.println("map的key:" + str + ",map的value: " + map.get(str));
}
System.out.println("==============================");
//2.2 只对map里面有哪些值感兴趣,不想知道key
Collection<String> values = map.values();
System.out.println(values.getClass());
for(String str : values) {
System.out.println(str);
}
System.out.println("++++++++++++++++++++++++++++++++++");
//2.3 key和value同时拿到; -> Entity(接口) -> Node(节点)
Set<Entry<String, String>> entrySet = map.entrySet();
for(Entry et : entrySet) { //每个et都是一个节点
String key = (String) et.getKey();
String value = (String) et.getValue();
System.out.println("key:" + key + ",value:" + value);
}
System.out.println("正常运行");
}
}
TreeMap
- 无序但是一定会排序,所以一定要实现Comparable接口,或者自定义比较器
基本用法
package com.qianfeng.xqc.day0309;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
/**
* map存储的 键值对,key value的存放方式
* - TreeMap集合有 key 和value值,它们成对出现,成为对应的Entry 对象
* - key值 可以是任意类型,无序,不可重复,不允许null值;用Set集合表示
* - value值 可以是任意类型,无序,可以重复,允许null值;用Collection集合表示
* 增:put(key,value);key不可重复 , value随便
* 删:tree.remove("1001");//根据key值删除
* 查:get(key); //只能通过key值获取value值; 不能通过value值获取key
* 改 : 不存在修改key; 如果key不一样,就代表是新增
* @author 淳
*
*/
public class DemoTreeMap {
public static void main(String[] args) {
//实例化了一个TreeMap对象
TreeMap<Integer, String> tree = new TreeMap<Integer, String>();
// * 增:put(key,value);key不可重复 , value随便
tree.put(1001, "张三");
tree.put(1002, "李四");
tree.put(6666, "jack");
tree.put(9999, "rose");
// tree.put(null, "nothing");//TreeMap的key不允许null
// * 删:tree.remove("1001");//根据key值删除
tree.remove(1001);
// * 改 : 不存在修改key; 如果key不一样,就代表是新增,key重复就是覆盖
tree.put(1002, "王二麻子");
// * 查:get(key); //只能通过key值获取value值; 不能通过value值获取key
System.out.println(tree.get(9999));
//查询; 1: 增强循环 2: 迭代器
System.out.println("--------key遍历----------");
//获取所有的key值,通过key值去遍历
Set<Integer> keySet = tree.keySet();
for(Integer i : keySet) {
System.out.println(i);
}
System.out.println("-------value遍历-------");
//获取所有的value值
Collection<String> values = tree.values();
for(String s : values) {
System.out.println(s);
}
System.out.println("-------key-value遍历-------");
//通过Entity(接口)的Node(节点)获取map集合中的key和value
Set<Entry<Integer, String>> entrySet = tree.entrySet();
for(Entry<Integer, String> et : entrySet) {
System.out.println("key:" + et.getKey() + ",value:" + et.getValue());
}
}
}
判断重复:实现Comparable接口或自定义比较器
package com.qianfeng.xqc.day0309;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
/**
* TreeMap 会进行排序,所以除了判断重复,一定要进行 顺序的比较和排列;
* TreeMap 需要自己去定义比较的方法
* @author 淳
*
*/
public class TestTreeMapComparable {
public static void main(String[] args) {
//TreeMap一定要进行比较,TreeMap指定比较器,在Person中实现Comparable接口
// TreeMap<Person,String> tree = new TreeMap<Person,String>();
//自定义比较器实现Comparator接口,重写compare方法
TreeMap<Person,String> tree = new TreeMap<Person,String>(new MyCompator());
//新建多个人对象
Person p1 = new Person("xqc", 23);
Person p2 = new Person("tom", 23);
Person p3 = new Person("jim", 23);
Person p4 = new Person("xqc", 23);
Person p5 = new Person("xqc", 24);
Person p6 = new Person("xx", 23);
Person p7 = new Person("tom", 43);
//将这些Person对象放入Map集合中
tree.put(p1,"a");
tree.put(p2,"c");
tree.put(p3,"b");
tree.put(p4,"d");
tree.put(p5,"d");
tree.put(p6,"d");
tree.put(p7,"d");
System.out.println(tree.size());
Set<Person> keySet = tree.keySet();
for(Iterator<Person> iterator = keySet.iterator();iterator.hasNext();) {
Person p = iterator.next();
System.out.println(p + "," + tree.get(p));
}
// test();
}
public static void test() {
TreeMap<String,Integer> Map = new TreeMap<String,Integer>();
//String不用去实现比较接口,String自己内部实现了Comparable
Map.put("b",1);
Map.put("a",2);
Map.put("c",3);
Map.put("e",4);
Map.put("s",5);
Set<Entry<String, Integer>> entrySet = Map.entrySet();
for(Entry<String, Integer> et : entrySet) {
System.out.println("key:" + et.getKey() + ",value:" + et.getValue());
}
}
}
/**
* 自定义比较器实现Comparator接口,重写compare方法
* 姓名年龄都相同才是同一个元素,所以先按姓名排序,姓名一样在按照年龄排序
* @author 淳
*
*/
class MyCompator implements Comparator<Person>{
//1 根据姓名判断是否同一个元素
//2 根据年龄判断
//姓名年龄都相同才是同一个元素,所以先按姓名排序,姓名一样在按照年龄排序
@Override
public int compare(Person o1, Person o2) {
if(o1.getName().compareTo(o2.getName()) == 0) {//姓名相同,按年龄排序
return o1.getAge() - o2.getAge();
}
//名字不一样
return o1.getName().compareTo(o2.getName());
}
}
class Person implements Comparable<Person>{
private String name;
private Integer age;
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void MapName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void MapAge(Integer age) {
this.age = age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
//TreeMap去进行比较,就是调用compareTo这个方法去比较;默认返回的都是0 ,代表相等;
@Override
public int compareTo(Person o) {
//根据姓名判断两个元素是否相等
//String如何去比较:直接使用字符串自己写好的比较规则,去对name进行比较;
return this.name.compareTo(o.name);
//根据年龄来比较呢?
// return this.age - other.age;
//-1 比原来的元素小 0 相等 1 比原来的元素大
// return 0;
}
}