import java.util.*;
public class MapDemo {
/**
*
Map接口:
* 1、键值对存储一-组对象
* 2、Key不能重复(唯一),Value可以重复
* 3、具体的实现类: HashMap LinkedHashMap Hashtable TreeMap
*
* 4、如何选择?
* 单线程?多线程?有序遍历? 按照一定顺序储存?......Hashtable用的比较少...
*
* 数据结构:数组、链表、二叉树、哈希表(数组+链表+二叉树)、栈、队列...
*
**/
public static void main(String[] args) {
// hashMap();
TreeMap();
}
/**
* HashMap --- 不能保证顺序恒久不变因为散列会重新打乱顺序
* 1.实现原理:数组+链表+二叉树(红黑树)JDK1.8
* 2.默认初始容量16,默认加载因子为0.75(意思就是若16个空间存了12个就不能存了,就得扩充)
* 3.存储原理:先把key对象通过hash()方法计算hash值,然后用这个hash数组对数组长度取余(来决定这个键值对在数组中存储的位置),
* 当这个位置为多个时变为链表,当链表长度大于等于8时就将这个链表变成一个红黑树结构存储,这样的目的是为了取值时更快。
* 4.扩充原理:当数组存储的数据超过75%时,当前数组的容量就左移一位(*2),其实就是原来的二倍,然后再去将原来的所有元素重新计算存储位置(耗性能,也是弊端),
* 所以扩充次数过多,就会很耗性能,因为每次扩充都得全部重新 ‘散列’,即重新计算每个元素的存储位置,所以在开发中药尽量减少扩充次数带来的性能问题。
* 5.线程不安全,适合在单线程中使用
*/
public static void hashMap(){
Map<Integer,String> map = new HashMap<>();
map.put(1,"lsq");
map.put(2,"lsw");
map.put(3,"lse");
System.out.println(map.size());
//通过KEY取值
System.out.println(map.get(1));
//遍历 key+value
Set<Map.Entry<Integer, String>> entries = map.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
System.out.println(entry.getKey()+": "+entry.getValue());
}
//遍历 key
Set<Integer> keys = map.keySet();
for (Integer key : keys) {
System.out.println(key);
}
//遍历 value
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
//foreach进行遍历 key+value
map.forEach((key,value)-> System.out.println("KEY->"+key+",VALUE->"+value));
//是否包含key或value
System.out.println(map.containsKey(5) ? "存在":"不存在");
System.out.println(map.containsValue("lsq") ? "存在":"不存在");
/**
* 此外还有根据key删除键值对
* 根据key替换值
* ....更多方法查看API
*/
}
/**
* Hashtable --- JDK1.0就开始了
* 和HashMap差不多,基于哈希表实现(数组+链表),
* 默认容量11,默认加载因子为0.75,
* 扩充方式:原数组大小左移一位再加一,就是*2+1
* 线程安全
* 1.与 HashMap 的区别?
*/
public static void hashTable(){
Map<String,String> map = new Hashtable<>();
map.put("one","lsq");
map.put("two","lsw");
map.put("three","lse");
map.forEach((key,value)-> System.out.println("KEY->"+key+",VALUE->"+value));
}
/**
* LinkedHashMap --- 继承了HashMap实现了接口
* 它具有可预知的迭代顺序。此实现与HashMap的不同之处在于,后者维护着-一个运行于所有条目的双重链接列表,意思就是无论你怎么散列,我都维护着一个永恒不变的顺序
*/
public static void linkedHashMap(){
Map<String,String> map = new LinkedHashMap<>();
map.put("one","lsq");
map.put("two","lsw");
map.put("three","lse");
map.forEach((key,value)-> System.out.println("KEY->"+key+",VALUE->"+value));
}
/**
* TreeMap --- TreeSet就是基于它实现的
* 基于红黑树(一种平衡二叉树)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparator进行排序,具体取决于使用的构造方法。
*/
public static void TreeMap(){
Map<String,String> map = new TreeMap<>();
map.put("one","lsq");
map.put("two","lsw");
map.put("three","lse");
map.forEach((key,value)-> System.out.println("KEY->"+key+",VALUE->"+value));
Map<animal,String> tree = new TreeMap<>();
tree.put(new animal("lsq",27),"cat1");
tree.put(new animal("lsw",21),"cat2");
tree.put(new animal("lse",29),"cat3");
/**
* 此处应当注意 --- 替换问题
*/
tree.put(new animal("lsq",29),"CAT");//因为以age属性排序,若age相同,就会用后者全部替换
tree.forEach((key,value)-> System.out.println("KEY->"+key+",VALUE->"+value));
}
/**
* 跟多点击查看源码和API接口文档......
*/
}
class animal implements Comparable<animal>{
private String name;
private int age;
public animal(String name, int age) {
this.name = name;
this.age = age;
}
public animal() {
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
animal cat = (animal) o;
return age == cat.age && Objects.equals(name, cat.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(animal o) {
//根据年龄排序
return this.age - o.age;
}
}
JDK1.8下的Map中的新接口
import java.util.HashMap;
import java.util.Map;
public class newMapDemo {
/**
* Map接口JDK1.8新增方法介绍
* @param args
*/
public static void main(String[] args) {
newMap();
}
/**
* JDK1.8新增了接口的默认方法,接口内直接实现的方法,继承就有
*/
public static void newMap(){
Map<Integer, String> map = new HashMap<>();
map.put(1,"one");
map.put(2,"two");
map.put(3,"three");
/**
* getOrDefault --- 获取不到key时返回一个默认值
*
* default V getOrDefault(Object key, V defaultValue) {
* V v;
* return (((v = get(key)) != null) || containsKey(key))
* ?
* v : defaultValue;
* }
*/
String s = map.get(4);
System.out.println(s);
String s2 = map.getOrDefault(4, "没有此键值对哦!");
System.out.println(s2);
/**
* putIfAbsent --- 只会添加不存在的key的键值对 key值存在就返回之前的值,不存在再调用put()方法,返回null
*
* default V putIfAbsent(K key, V value) {
* V v = get(key);
* if (v == null) {
* v = put(key, value);
* }
* return v;
* }
*/
String getMapKeyEquals3 = map.put(3, "new three");
System.out.println(getMapKeyEquals3);//结果是字符串'three',返回的是覆盖前的值
System.out.println(map.get(3));//结果是字符串'new three',因为同一个key值被覆盖了
String new_new_three = map.putIfAbsent(3, "new new three");
System.out.println(new_new_three);//结果是字符串'new three',因为这个key值已存在
String new_new_new_three = map.putIfAbsent(4, "four");
System.out.println(new_new_new_three);//结果是null,因为这个key值不存在,调用了put()方法,并返回了null
System.out.println(map.get(4));//结果是字符串'four'
map.forEach((k,v)-> System.out.println(k+v));
/**
* remove(key,value),只有key和value都和集合中的一项键值对相同时才调用remove(key)方法,删除并返回true,否则返回false
* 相对于remove(key)更加严谨了
*
* default boolean remove(Object key, Object value) {
* Object curValue = get(key);
* if (!Objects.equals(curValue, value) ||
* (curValue == null && !containsKey(key))) {
* return false;
* }
* remove(key);
* return true;
* }
*/
System.out.println(map.remove(4,"not four"));//结果是false
System.out.println(map.remove(4,"four"));//结果是true
/**
* replace(k,v)
* replace(k,v,v)
* 先判断key不为空,且存在,都是调用的put(k,v),直接覆盖。
*/
map.replace(3,"3");
System.out.println(map.get(3));
map.replace(3,"3","new-3");
System.out.println(map.get(3));
/**
* compute --对某一key值进行计算
* computeIfAbsent -- 如果key为null,将计算后的结果作为value再调用put(k,v)
*/
map.compute(1,(k,v)->v+"test");
System.out.println(map.get(1));
map.computeIfAbsent(4,k->k+"test2");
System.out.println(map.get(4));
/**
* merge -- 合并参数
* default V merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction)
*
*/
map.merge(1,"onetest",(ov,nv)->ov.concat(nv));
System.out.println(map.get(1));
}
}