Map
1、概述
- Map与Collection并列存在。用于保存具有映射关系的数据:key-value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应 的类,须重写hashCode()和equals()方法
- 常用String类作为Map的“键”
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到 唯一的、确定的 value
- Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用频率最高的实现类
- 双列数据,存储key-value对的数据 ----类型高中的函数:y = f(x)
- 子类
- HashMap----作为Map的主要实现类----线程不安全,效率高,能存储null的key-value
- LinkedHashMap----HashMap子类
- TreeMap
- Hashtable:古老的实现类----线程安全,效率低
- Properties----常用来处理配置文件----ket-value都是String
- HashMap----作为Map的主要实现类----线程不安全,效率高,能存储null的key-value
2、Map结构的理解
- key—用set存储:因为key是无序不可重复的—刚好对应了set的特性----须重写hashCode()和equals()方法
- value----用collection存储----须equals()方法
- entry—每一个(key,value)都是一个entry对象—entry是不可重复无序的(set存储)
3、HashMap的底层原理(*)
3–1jdk7的底层原理
- HashMap map = new HashMap();-----在实例化后,底层创建了一个长度为16的一维数组Entry[] table
- map.put(key1,value1);----可能已经执行了多次put
- ----首先,调用key1所在的类的hashCode()计算 key1 的哈希值,此哈希值通过某种算法以后,得到在Entry数组中存放位置。
- ----如果此位置上的数据为空,此时的key1-value1添加成功
- -----如果此位置上的数据不为空(意味着此位置上有一个或多个以链表形式存在的数据),比较key1和以及存在的一个或多个数据的哈希值:
- 如果key1的哈希值与已存在的数据的哈希值都不一样----添加成功
- 如果key1的哈希值与已存在的数据的某一个哈希值都一样时,调用key1所在类的equals()—返回为false—添加成功—以链式的存储关系
- 如果key1的哈希值与已存在的数据的某一个哈希值都一样时,调用key1所在类的equals()—返回为true----用value1 替换 value2
- 在不断添加过程中,会涉及到扩容的问题:扩容到原来的2倍,并将原有的数据复制过来
- 源码分析
- 数组的最大容量:16
- loadFactor–>默认加载因子:0.75
- threshold–>临界值:12–>长度超过12(且你想要放的位置不为空时),开始扩容—扩容成原来的二倍
- 链表放入新元素时采用头插法
3–2、jdk8底层原理(相对于jdk7不同)
- new HashMap():底层没有创建长度为16的数组----懒汉式创建数组
- jdk8底层的数组是:Node[],而非Entry[]
- 首次调用put()方法时,底层创建一个长度为16的数组
- jdk7底层结构为:数组+链表-----jdk8底层为:数组+链表+红黑树
- 当数组的某一个索引位置上的元素一链式形式存在的个数 > 8 && 当前的数组长度 > 64 时,此时此索引位置上的所有数据改为使用红黑树存储
- 源码分析
- HashMap底层典型属性的属性的说明:
- DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
- DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75
- threshold:扩容的临界值,=容量*填充因子:16 * 0.75 => 12
- TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
- MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
- jdk8采用的是链表尾插法
4、LinkedHashMap(双向链表)
- 会保留添加时的顺序—不会打乱
- LinkedHashMap底层使用的结构与HashMap相同,因为LinkedHashMap继承于HashMap.
区别就在于:LinkedHashMap内部提供了Entry,替换HashMap中的Node.
5、Map常用的方法
-
添加、删除、修改操作:
-
Object put(Object key,Object value)//:将指定key-value添加到(或修改)当前map对象中 void putAll(Map m)//:将m中的所有key-value对存放到当前map中 Object remove(Object key)//:移除指定key的key-value对,并返回value void clear()//:清空当前map中的所有数据
-
@Test public void test1(){ Map m = new HashMap(); m.put("zzj",19); m.put("lmg",21); m.put("xxl",19); //添加元素 System.out.println(m); Map m2 = new HashMap(); m2.putAll(m); //将m中的所有key-value对存放到当前map中 System.out.println(m2); Object o = m.remove("zzj"); //移除指定key的key-value对,并返回value System.out.println(o); System.out.println(m); m.clear(); //只是清空数据---不会赋值给null System.out.println(m); }
-
-
元素查询的操作:
-
Object get(Object key)//:获取指定key对应的value boolean containsKey(Object key)//:是否包含指定的key boolean containsValue(Object value)//:是否包含指定的value int size()//:返回map中key-value对的个数 boolean isEmpty()//:判断当前map是否为空 boolean equals(Object obj)//:判断当前map和参数对象obj是否相等
-
@Test public void test2(){ Map m = new HashMap(); m.put("zzj",19); m.put("lmg",21); m.put("xxl",19); //添加元素 System.out.println(m); Object o = m.get("zzj"); System.out.println(o); //获取指定key对应的value boolean b = m.containsKey("zzj"); //是否包含指定的key System.out.println(b); boolean b1 = m.containsValue(19); //是否包含指定的value---找到一个就停止,后面不看 System.out.println(b1); System.out.println(m.size()); //返回map中key-value对的个数 boolean b2 = m.isEmpty(); //判断当前map是否为空 System.out.println(b2); Map m2 = new HashMap(); m2.putAll(m); System.out.println(m.equals(m2));//:判断当前map和参数对象obj是否相等 }
-
-
元视图操作的方法:
-
Set keySet()//:返回所有key构成的Set集合 Collection values()//:返回所有value构成的Collection集合 Set entrySet()//:返回所有key-value对构成的Set集合
-
@Test public void test3(){ Map m = new HashMap(); m.put("zzj",19); m.put("lmg",21); m.put("xxl",19); //添加元素 System.out.println(m); //遍历key值 Set set = m.keySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //遍历value Collection collection = m.values(); for (Object o : collection){ System.out.println(o); } //遍历键值对 Set set1 = m.entrySet(); Iterator iterator1 = set1.iterator(); while (iterator1.hasNext()){ Object o = iterator1.next(); Map.Entry e = (Map.Entry) o; System.out.println(e.getKey() + "---->" + e.getValue()); } }
-
6、TreeMap
-
概述
- TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。 TreeMap 可以保证所有的 Key-Value 对处于有序状态。
- TreeSet底层使用红黑树结构存储数据
- TreeMap 的 Key 的排序:
- 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
- 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
- TreeMap判断两个key相等的标准:两个key通过compareTo()方法或 者compare()方法返回0。
-
代码实现
-
//向TreeMap中添加key-value时,key必须来着同一个类创建的对象 //因为要按照key进行排序--自然排序--定制排序 //自然排序 @Test public void test1(){ TreeMap map = new TreeMap(); String str1 = "zzj"; String str2 = "lmg"; String str3 = "xxl"; String str4 = "zhh"; map.put(str1,19); map.put(str2,21); map.put(str3,20); map.put(str4,19); Set set = map.entrySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()){ Object o = iterator.next(); Map.Entry e = (Map.Entry) o; System.out.println(e.getKey() + "--->" + e.getValue()); } } //定制排序 @Test public void test3() { TreeMap map = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof String && o2 instanceof String) { String s = (String) o1; String s1 = (String) o2; return s.compareTo(s1); } throw new RuntimeException("输入的不匹配"); } }); String str1 = "zzj"; String str2 = "lmg"; String str3 = "xxl"; String str4 = "zhh"; map.put(str1, 19); map.put(str2, 21); map.put(str3, 20); map.put(str4, 19); Set set = map.entrySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { Object o = iterator.next(); Map.Entry e = (Map.Entry) o; System.out.println(e.getKey() + "--->" + e.getValue()); } }
-
7、Properties(Hashtable子类)
-
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
-
由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
-
存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法
-
Properties pros = new Properties(); pros.load(new FileInputStream("jdbc.properties")); String user = pros.getProperty("user"); System.out.println(user)
8、Collections工具类
-
Collections 是一个操作 Set、List 和 Map 等集合的工具类
-
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作, 还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
-
排序操作:(均为static方法)
- reverse(List):反转 List 中元素的顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
-
查找、替换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回 给定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
-
代码实现
-
@Test public void test1(){ List list = new ArrayList(); list.add(18); list.add(19); list.add(20); list.add(21); list.add(19); System.out.println("===========随机处理============"); Collections.shuffle(list);//随机处理 System.out.println(list); System.out.println("===========反转============"); Collections.reverse(list); //反转list System.out.println(list); System.out.println("===========升序============"); Collections.sort(list); System.out.println(list); System.out.println("===========升序后反转倒叙============"); Collections.sort(list); Collections.reverse(list); //反转list System.out.println(list); System.out.println("===========交换1,2============"); Collections.swap(list,1,2); System.out.println(list); System.out.println("===========根据元素的自然顺序,返回给定集合中的最大元素 ============"); Object o = Collections.max(list); System.out.println(o); System.out.println("===========根据元素的自然顺序,返回给定集合中的最大元素 ============"); o = Collections.min(list); System.out.println(o); System.out.println("===========返回指定集合中指定元素的出现次数 ============"); int num = Collections.frequency(list, 19); System.out.println(num); System.out.println("===========将src中的内容复制到dest中 ============"); //这样写报异常了 // List list1 = new ArrayList(); // Collections.copy(list1,list); //IndexOutOfBoundsException: Source does not fit in dest //原因是copy是 list1 的容量要大于 list才可copy成功---且是替换 List list1 = Arrays.asList(new Object[list.size()]); //将对象数组给list1---切对象数组的长度为list的size Collections.copy(list1,list); System.out.println(list1); System.out.println("===========使用新值替换 List 对象的所有旧值 ============"); List list2 = new ArrayList(); list2.add(1); list2.add(2); System.out.println(list2); System.out.println(Collections.replaceAll(list2, 1, 132)); System.out.println(list2); } //代码结果------------------------------- /* ===========随机处理============ [20, 18, 19, 21, 19] ===========反转============ [19, 21, 19, 18, 20] ===========升序============ [18, 19, 19, 20, 21] ===========升序后反转倒叙============ [21, 20, 19, 19, 18] ===========交换1,2============ [21, 19, 20, 19, 18] ===========根据元素的自然顺序,返回给定集合中的最大元素 ============ 21 ===========根据元素的自然顺序,返回给定集合中的最大元素 ============ 18 ===========返回指定集合中指定元素的出现次数 ============ 2 ===========将src中的内容复制到dest中 ============ [21, 19, 20, 19, 18] ===========使用新值替换 List 对象的所有旧值 ============ [1, 2] true [132, 2] */
-
-
Map存储数据的特点是什么?并指明key,value,entry存储数据的特点。
双列数据,存储key-value对数据。
------key:无序的、不可重复的—>Set存储
------value:无序的、可重复的 –->Collection存储
------key-value:无序的、不可重复---->Set存储