Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

一、Map回顾

    Map,又称映射表,是将键映射到值的对象。有四种实现Map接口并且经常使用的Map集合为:HashMap,TreeMap,Hashtable 和 LinkedHashMap.

泥瓦匠记忆宫殿:

    1、一个映射不包含重复的键

    2、每个键最多只能映射到一个值。

MapClassHierarchy-600x354

二、HashMap

    HashMap是基于哈希表的Map接口的实现。其对键进行散列,散列函数只能作用于键。下面模拟下,公司员工和找员工的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.HashMap;
import java.util.Map;
 
class Employee
{}
 
public class HaspMap01
{
     public static void main(String[] args)
     {
         Map< String , Employee> employees = new HashMap< String , Employee>();
         employees.put("1206010035", new Employee());
         System.out.println(employees);
         
         String number = "1206010035";
         System.out.println(employees.get(number));
     }
}

Run一下,大家可以见到结果:put方法,可以将键值映射添加进表。get方法则返回指定键所映射的值。从他们 hashCode 可以看出是同一个对象。

    HaspMap的键必须唯一,同样其同一个键不能存放两个值,如果对同一个键两次调用put方法,第二个值会取代第一个值。同样是允许使用 null 值和 null 键。下面泥瓦匠用一个简单的例子解释下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package javaBasic.collection.map;
 
import java.util.HashMap;
import java.util.Map;
 
 
public class HaspMap02
{
     @SuppressWarnings({ "unchecked", "rawtypes" })
     public static void main(String[] args)
     {
         Map map = new HashMap< String , String>();
         map.put(null, "null01");
         map.put(null, "null02");
         System.out.println(map);
         System.out.println(map.get(null));
     }
}

结果如下:

?
1
2
{null=null02}
null02

由此可见,第一个值被第二个值所替换了。

下面有三点是HashMap重要之处:

1、HashMap的构造函数

   HaspMap构造函数涉及两个参数:初始容量和加载因子。初试容量是哈希表创建时的其中桶的含量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。这两个参数都是影响HashMap的性能。默认构造一个具有默认初始容量 (16) 和默认加载因子 (0.75)。默认加载因子 (.75) 在时间和空间成本上是一种折衷的考虑。

2、和上次总结的Set都差不多,这个HashMap线程是不安全不同步的。如果想防止意外发生,则设置成同步即可:

?
1
Map m = Collections.synchronizedMap(new HashMap(...));

3、不同步的话,意味着存在快速失败导致的并发修改异常。

下面看一个复杂例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package javaBasic.collection.map;
 
import java.util.HashMap;
import java.util.Map.Entry;
 
class A
{
     public boolean equals(Object obj)
     {
         return true;
     }
}
 
class B
{
     public int hashCode()
     {
         return 1;
     }
}
 
class C
{
     public int hashCode()
     {
         return 2;
     }
 
     public boolean equals(Object obj)
     {
         return true;
     }
}
 
public class HashMap03
{
     public static void main(String[] args)
     {
         HashMap< A , Integer> hashMapA = new HashMap< A , Integer>();
         hashMapA.put(new A(), 10);
         hashMapA.put(new A(), 5);
         
         System.out.println("HashMapA Elements:");
         System.out.print("\t" + hashMapA + "\n");
         
         // loop HashMapA
         for(Entry< A , Integer> entryA : hashMapA.entrySet())
         {
             System.out.println(entryA.getKey().toString()+"-"+entryA.getValue());
         }
         
         HashMap< B , Integer> hashMapB = new HashMap< B , Integer>();
         hashMapB.put(new B(), 10);
         hashMapB.put(new B(), 5);
         
         System.out.println("HashMapB Elements:");
         System.out.print("\t" + hashMapB + "\n");
         
         // loop HashMapB
         for(Entry< B , Integer> entryB : hashMapB.entrySet())
         {
             System.out.println(entryB.getKey().toString()+"-"+entryB.getValue());
         }
         
         HashMap< C , Integer> hashMapC = new HashMap< C , Integer>();
         hashMapC.put(new C(), 10);
         hashMapC.put(new C(), 5);
         
         System.out.println("HashMapC Elements:");
         System.out.print("\t" + hashMapC + "\n");
         
         // loop HashMap
         for(Entry< C , Integer> entryC : hashMapC.entrySet())
         {
             System.out.println(entryC.getKey().toString()+"-"+entryC.getValue());
         }
     }
}

运行一下,可以看到以下结果:


由此可见,其中和 Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较 中涉及的知识点一致:

集合判断两个元素相等不单单是equals方法,并且必须hashCode()方法返回值也要相等。


三、TreeMap

    TreeMap使用树结构实现(红黑树),集合中的元素进行排序,但是添加、删除和包含的算法复杂度为O(log(n))。其实Map特性基本都是一致的,比如看下面的简单例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TreeMap01
{  
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public static void main(String[] args)
     {
         Map map = new TreeMap();
         map.put("1", "1");
         map.put("4", "4");
         map.put("2", "2");
         map.put("2", "3");
         System.out.println(map);
     }
}

结果如下:

?
1
{1=1, 2=3, 4=4}

从中我们可以看出

1、TreeMap实现了SortedMap,顾名思义,其表示为有排序的集合。

2、同样其同一个键不能存放两个值,如果对同一个键两次调用put方法,第二个值会取代第一个值。

四、总结

HashMap与TreeMap
      1、HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。HashMap中元素的排列顺序是不固定的)。
      2、  HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。
      3、在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。 这个TreeMap没有调优选项,因为该树总处于平衡状态。
相关文章
|
1月前
|
Java 虚拟化 容器
(Java)Java里JFrame窗体的基本操作(容器布局篇-1)
容器 容器,我的理解是可以包容其他东西的玩意。它可以是一个盒子,可以是一个虚拟化的物品,可只要能包裹住其他存在质体的东西,那么都可以称作是容器。例如:JPanel组件和JScollPane组件两者都是容器也是组件。 既然有容器,那么容器中的布局就必不可少了。不然不规矩的摆放物品,人类看不习惯,我也看不习惯 ???? 本篇内容,将说明java JFrame窗体里容器中几类布局。 说明:所有在JFrame窗体里的容器布局都会使用setLayout()方法,采用的布局参数都将放进这个方法里 绝对布局 调用窗体容器
91 1
|
2月前
|
安全 Java
Java之泛型使用教程
Java之泛型使用教程
236 10
|
4月前
|
安全 Java API
在Java中识别泛型信息
以上步骤和示例代码展示了怎样在Java中获取泛型类、泛型方法和泛型字段的类型参数信息。这些方法利用Java的反射API来绕过类型擦除的限制并访问运行时的类型信息。这对于在运行时进行类型安全的操作是很有帮助的,比如在创建类型安全的集合或者其他复杂数据结构时处理泛型。注意,过度使用反射可能会导致代码难以理解和维护,因此应该在确有必要时才使用反射来获取泛型信息。
216 11
|
11月前
|
存储 安全 Java
Java 集合框架中的老炮与新秀:HashTable 和 HashMap 谁更胜一筹?
嗨,大家好,我是技术伙伴小米。今天通过讲故事的方式,详细介绍 Java 中 HashMap 和 HashTable 的区别。从版本、线程安全、null 值支持、性能及迭代器行为等方面对比,帮助你轻松应对面试中的经典问题。HashMap 更高效灵活,适合单线程或需手动处理线程安全的场景;HashTable 较古老,线程安全但性能不佳。现代项目推荐使用 ConcurrentHashMap。关注我的公众号“软件求生”,获取更多技术干货!
196 3
|
5月前
|
存储 缓存 安全
Java 集合容器常见面试题及详细解析
本文全面解析Java集合框架,涵盖基础概念、常见接口与类的特点及区别、底层数据结构、线程安全等内容。通过实例讲解List(如ArrayList、LinkedList)、Set(如HashSet、TreeSet)、Map(如HashMap、TreeMap)等核心组件,帮助读者深入理解集合容器的使用场景与性能优化。适合准备面试或提升开发技能的开发者阅读。
104 0
|
5月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
295 3
|
5月前
|
缓存 Java API
Java 集合容器实操技巧与案例详解
本教程基于Java 8+新特性和现代开发实践,深入讲解Java集合容器的实操技巧。通过具体场景演示Stream API数据处理、ConcurrentHashMap并发控制、LinkedHashMap实现LRU缓存、TreeSet自定义排序等高级特性。同时涵盖computeIfAbsent优化操作、EnumMap专用集合使用、集合统计与运算(交集、并集、差集)等内容。代码示例丰富,助力掌握高效编程方法。[点击获取完整代码](https://pan.quark.cn/s/14fcf913bae6)。
80 0
|
9月前
|
存储 缓存 安全
Java HashMap详解及实现原理
Java HashMap是Java集合框架中常用的Map接口实现,基于哈希表结构,允许null键和值,提供高效的存取操作。它通过哈希函数将键映射到数组索引,并使用链表或红黑树解决哈希冲突。HashMap非线程安全,多线程环境下需注意并发问题,常用解决方案包括ConcurrentHashMap和Collections.synchronizedMap()。此外,合理设置初始化容量和加载因子、重写hashCode()和equals()方法有助于提高性能和避免哈希冲突。
554 17
Java HashMap详解及实现原理
|
9月前
|
存储 安全 算法
Java容器及其常用方法汇总
Java Collections框架提供了丰富的接口和实现类,用于管理和操作集合数据。
161 2
Java容器及其常用方法汇总
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####