Java 容器 & 泛型:五、HashMap 和 TreeMap的自白-阿里云开发者社区

开发者社区> bysocket> 正文

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

简介:
+关注继续查看

一、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没有调优选项,因为该树总处于平衡状态。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【Java入门提高篇】Day20 Java容器类详解(三)List接口
  今天要说的是Collection族长下的三名大将之一,List,Set,Queue中的List,它们都继承自Collection接口,所以Collection接口的所有操作,它们自然也是有的。   List,Set,Queue,分别是列表,集合,队列的意思,代表着Collection家族下的三种不同的势力,它们各有所长,也各有所短,就像骑兵,步兵和水兵,各有各的优势,并没有谁一定比谁更好的说法,合适的才是最好的。
1063 0
【Java入门提高篇】Day24 Java容器类详解(七)HashMap源码分析(下)
  前两篇对HashMap这家伙的主要方法,主要算法做了一个详细的介绍,本篇主要介绍HashMap中默默无闻地工作着的集合们,包括KeySet,values,EntrySet,以及对应的迭代器:HashIterator,KeyIterator,ValueIterator,EntryIterator和 fast-fail 机制。
980 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4512 0
【Java入门提高篇】Day28 Java容器类详解(十)LinkedHashMap详解
  今天来介绍一下容器类中的另一个哈希表———》LinkedHashMap。这是HashMap的关门弟子,直接继承了HashMap的衣钵,所以拥有HashMap的全部特性,并青出于蓝而胜于蓝,有着一些HashMap没有的特性。
1097 0
【阿里在线技术峰会】魏鹏:基于Java容器的多应用部署技术实践
在首届阿里巴巴在线峰会上,阿里巴巴中间件技术部专家魏鹏为大家带来了题为《基于Java容器的多应用部署技术实践》的分享,主要分享内容首先是阿里Java容器的发展历程,接着与大家分享目前Java容器的基础架构,最后与大家探讨经过这样的改变之后,它能够完成的一些高阶的特性。
8076 0
DockOne微信分享(六十八):应用容器env化实战
本文讲的是DockOne微信分享(六十八):应用容器env化实战【编者的话】随着Docker技术的火热发展, Docker在代码构建发布中扮演着越来越重要的角色。Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到流行的Linux机器上。Docker非常适用于如下场景:
2328 0
【Java入门提高篇】Day18 Java容器类详解(一)Collection接口
  今天来看看Java里的一个大家伙,那就是容器。   所谓容器,就是专门用来装对象的东西,如果你学过高数,没错,就跟里面说的集合是一个概念,就是一堆对象的集合体,但是集合类是容器类中的一个子集,为了区别表示,所以还是叫容器类,之后所说的集合类只是容器里的一个子集,之后会有详细介绍。
1095 0
+关注
bysocket
bysocket.com | 加我wx bysocket01,进纯技术交流群
286
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载