From cbf03608b0d0bf69774e685420090c327aac2059 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 19 Sep 2022 18:27:18 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E5=90=88map,HashMap=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E5=AD=A6=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/collection/HashMapTest.java | 99 +++++++++++ .../java_learning/collection/MapTest.java | 166 ++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java new file mode 100644 index 0000000..4d0ebc6 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java @@ -0,0 +1,99 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.HashMap; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-19 17:03 + * @Description: TODO 测试HashMap的树化和反树化 + * @Version: 1.0 + */ +public class HashMapTest { + + @Test + public void test1(){ + + //这里为了演示的效果,我们造一个特殊的类,这个类的hashCode()方法返回固定值1 + //因为这样就可以造成冲突问题,使得它们都存到table[1]中 + HashMap map = new HashMap<>(); + for (int i = 1; i <= 11; i++) { + map.put(new MyKey(i), "value"+i);//树化演示 + } + + } + + @Test + public void test2(){ + + HashMap map = new HashMap<>(); + for (int i = 1; i <= 11; i++) { + map.put(new MyKey(i), "value"+i); + } + for (int i = 1; i <=11; i++) { + map.remove(new MyKey(i));//反树化演示 + } + + } + + @Test + public void test3(){ + + HashMap map = new HashMap<>(); + for (int i = 1; i <= 11; i++) { + map.put(new MyKey(i), "value"+i); + } + + for (int i = 1; i <=5; i++) { + map.remove(new MyKey(i)); + }//table[1]下剩余6个结点 + + for (int i = 21; i <= 100; i++) { + map.put(new MyKey(i), "value"+i);//添加到扩容时,反树化 + } + + } + +} + + +class MyKey{ + int num; + + public MyKey(int num) { + super(); + this.num = num; + } + + @Override + public int hashCode() { + //容量小于20全放一个里面 + if(num<=20){ + return 1; + }else{ + //大于30之后尽可能分开 + final int prime = 31; + int result = 1; + result = prime * result + num; + return result; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MyKey other = (MyKey) obj; + if (num != other.num) + return false; + return true; + } + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java new file mode 100644 index 0000000..509ed1f --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java @@ -0,0 +1,166 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-19 15:35 + * @Description: + * TODO Map及其实现类:HashMap、HashTable、LinkedHashMap、TreeMap、Properties + * 1)Map: + * 1.这些实现类均继承自java.util.Map接口 + * 2.使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中; + * 若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。 + * 3.Map的遍历,不能支持foreach,因为Map接口没有继承java.lang.Iterable接口,也没有实现Iterator iterator()方法。 + * 但是可以分别遍历其key(keySet()方法)和value(values方法),也可以成对遍历(entrySet()方法) + * 4.Map.Entry是Map接口的内部接口。每一种Map内部有自己的Map.Entry的实现类。 + * 在Map中存储数据,实际上是将Key---->value的数据存储在Map.Entry接口的实例中,再在Map集合中插入Map.Entry的实例化对象 + * 2)HashMap: + * 1.底层是哈希表 数组加链表 JDK1.7散列表table[index]也称为bucket桶,其中table是一个HashMap.Entry是一个链表,HashMap.Entry中还存放着next指针,存放相同hashcode值的元素 + * JDK1.8封装为HashMap.Node类型或HashMap.TreeNode类型,它俩都直接或间接的实现了Map.Entry接口。即table[index]下的映射关系可能串起来一个链表或一棵红黑树(自平衡的二叉树)。 + * 链表长度大于8(且总容量大于等于64,不大的话会优先扩容而不是树化)转为红黑树(一种解释是节点规律服从泊松分布,经过计算得出这个值会比较好),树节点数小于6退化为链表 + * 2.评价两个key是否相等的指标是其hashcode相等,且equal方法返回true,所以存放的对象必须实现hashcode和equal方法 + * 3.线程不安全的,并允许使用 null 值和 null 键。 + * 4.默认初始化长度1<<4 即16(一定是2的倍数).每次扩容变为原来的两倍,未避免分布不均匀增加了扰动计算 + * 5.哈希算法:使用位运算代替取模运算(前提:容量length一定是2^n) 源码:hashcode&(length-1) X %2^n=X &(2^n-1) + * 3)HashTable: + * 1.底层实现是哈希表 + * 2.评价两个key是否相等的指标是其hashcode相等,且equal方法返回true,所以存放的对象必须实现hashcode和equal方法 + * 3.线程安全的,任何非 null 对象都可以用作键或值。 + * 4.默认初始化长度11(素数),内次扩容变为原来的2n+1倍,扩容结果也为奇数,素数使得节点取模更加均匀,分散效果越好 + * 5.哈希算法:在保证是正数的情况下直接取模 源码:(hashcode & 0x7FFFFFFF)%table.length + * 4)LinkedHashMap: + * 1.LinkedHashMap是HashMap的子类 + * 2.与HashMap的不同在于:前者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。 + * 5)TreeMap: + * 1.基于红黑树(Red-Black tree)的 NavigableMap 实现。 + * 2.该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。 + * 6)Properties: + * 1.Properties 类是 Hashtable 的子类,Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 + * 2.存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。 + * 7)HashSet与Map的关系: + * 1.Set的内部实现其实是一个Map。即HashSet的内部实现是一个HashMap,TreeSet的内部实现是一个TreeMap,LinkedHashSet的内部实现是一个LinkedHashMap。 + * 2.Set中只有一个元素,又是怎么变成(key,value)的呢? + * 源码实现:private static final Object PRESENT = new Object(); + * public boolean add(E e) { + * return map.put(e, PRESENT)==null; + * } + * public Iterator iterator() { + * return map.keySet().iterator(); + * } + * @Version: 1.0 + */ +public class MapTest { + + + //HashMap的put覆盖测试,和可以存放null值测试 + @Test + public void test(){ + HashMap map = new HashMap<>(); + map.put("张三", 10000.0); + //key相同,新的value会覆盖原来的value + //因为String重写了hashCode和equals方法 + map.put("张三", 12000.0); + map.put("李四", 14000.0); + //HashMap支持key和value为null值 + String name = null; + Double salary = null; + map.put(name, salary); + + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry);//null=null;李四=14000.0;张三=12000.0 + } + } + + //LinkedHashMap的插入顺序测试 + @Test + public void test1(){ + LinkedHashMap map = new LinkedHashMap<>(); + map.put("张三", 10000.0); + //key相同,新的value会覆盖原来的value + //因为String重写了hashCode和equals方法 + map.put("张三", 12000.0); + map.put("李四", 14000.0); + //HashMap支持key和value为null值 + String name = null; + Double salary = null; + map.put(name, salary); + + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry); //张三=12000.0;李四=14000.0;null=null + } + } + + //TreeMap自然顺序比较 + @Test + public void test2() { + TreeMap map = new TreeMap<>(); + map.put("Jack", 11000); + map.put("Alice", 12000); + map.put("zhangsan", 13000); + map.put("baitao", 14000); + map.put("Lucy", 15000); + + //String实现了Comparable接口,默认按照Unicode编码值排序 + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry); + /* + Alice=12000 + Jack=11000 + Lucy=15000 + baitao=14000 + zhangsan=13000 + */ + } + } + + //TreeMap实现comparator比较器顺序 + @Test + public void test3() { + //指定定制比较器Comparator,按照Unicode编码值排序,但是忽略大小写 + TreeMap map = new TreeMap<>(new Comparator() { + + @Override + public int compare(String o1, String o2) { + return o1.compareToIgnoreCase(o2); + } + }); + map.put("Jack", 11000); + map.put("Alice", 12000); + map.put("zhangsan", 13000); + map.put("baitao", 14000); + map.put("Lucy", 15000); + + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry); + /* + Alice=12000 + baitao=14000 + Jack=11000 + Lucy=15000 + zhangsan=13000 + */ + } + } + + //properties方法测试 + @Test + public void test4(){ +// Properties properties1 = new Properties(); +// properties1.setProperty() + Properties properties = System.getProperties(); + String p2 = properties.getProperty("file.encoding");//当前源文件字符编码 + System.out.println(p2); + } + + + +}