Java核心技术-映射
集是一个集合,它可以快速地查找现有的元素。但是,要查看一个元素,需要有要查找元素的精确副本。这不是一种非常通用的查找方式。通常,我们知道某些键的信息,并想要查找与之对应的元素。映射(map)数据结构就是为此设计的。映射用来存放键/值对。如果提供了键,就能够查找到值。
基本映射操作
Java类库为映射提供了两个通用的实现:HashMap和TreeMap。这两个类都实现了Map接口。
散列映射对键进行散列,树映射用键的整体顺序对元素进行排序,并将其组织成搜索树。散列或比较函数职能作用于键。于键关联的值不能进行散列或比较。
散列稍微快一些,如果不需要按照排序顺序访问键,就最好选择散列。
下列代码将为存储的员工信息建立一个散列映射:
Map<String, Employee> staff = new HashMap<>(); // HashMap implements Map
Employee harry = new Employee("Harry Hacker");
staff.put("987-98-9996", harry);
每当往映射中添加对象时,必须同时提供一个键。在这里,键是一个字符串,对应的值是Employee对象。
要想检索一个对象,必须使用(因而,必须记住)一个键。
String id = "987-98-9996";
e = staff.get(id);
如果在映射中没有与定键对应的消息,get将返回null。null返回值可能并不方便。有时可以有一个好的默认值,用作为映射中不存在的键。然后使用getOrDefault方法。
Map<String, Integer> scores = ...;
int score = scores.getOrDefault(id,0); // Gets 0 if the id is not present
键必须是唯一的。不能对同一个键存放两个值。如果对同一个键两次调用put方法,第二个值就会取代第一个值。实际上,put将返回用这个键参数存储的上一个值。
remove方法用于从映射中删除给定键对应的元素。size方法用于返回映射中的元素数。
要迭代处理映射的键和值,最容易的方法是使用forEach方法。
更新映射项
处理映射时的一个难点就是更新映射项。正常情况下,可以得到与一个键关联的原值,完成更新,再放回更新后的值。不过,必须考虑一个特殊情况,即键第一次出现。下面来看一个例子,使用一个映射统计一个单词再文件中出现的频度。看到单词(word)时,我们将计数器增1,如下所示:
counts.put(word, counts.getOrDefault(word) + 1)
这是可以的,不过一种情况除外:就是第一次看到word时。在这种情况下,get会返回null,因此会出现NullPointerException异常。
作为一个简单的补救,可以使用getOrDefault方法:
counts.put(word, counts.get(word, 0) + 1);
另一个方法是首先调用putIfAbsent方法。只有当键原先存在时才会放入一个值。
counts.putInfAbsent(word, 0 );
counts.put(word,counts.get(word) + 1);
不过还可以做得更好。merge方法可以简化这个常见的操作。如果键原先不存在,下面的调用:
counts.merge(word, 1,Integer::sum);
将把word与1关联,否则使用Integer::sum函数组合原值和1(也就是将原值与1求和)。
映射视图
集合框架不认为映射本身是一个集合。(其他数据结构框架认为映射是一个键/值对集合,或者是由键索引的值集合。)
弱散列映射
设计WeakHashMap类是为了解决一个有趣的问题。如果有一个值,对应的键已经不再使用了,将会出现什么情况呢?
首先,垃圾回收器跟踪活动的对象。只要映射对象是活动的,其中的所有桶也是活动的,它们不能被回收。
WeakHashMap使用弱引用(weak references)保存键。WeakReference对象将引用保存到另外一个对象中,在这里,就是散列键。对于这种类型的对象,垃圾回收器用一种特有的方式进行处理。通常,如果垃圾回收器发现某个特定的对象已经没有他人引用了,就将其回收。然而,如果某个对象只能由WeakReference引用,垃圾回收器仍然回收它,但要将引用这个对象的弱引用放入队列中。WeakHashMap将周期性地检查队列,以便找出新添加地弱引用。一个弱引用进入队列意味着这个键不再被他人使用,并且已经被收集起来。于是,WeakHashMap将删除对应的条目。
链接散列集与映射
链接散列映射将用访问顺序,而不是插入顺序,对映射条目进行迭代。每次调用get或put,受到影响的条目将从当前的位置删除,并放到条目链表的尾部(只有条目在链表中的位置会受影响,而散列表中的桶不会受影响。一个条目总位于与键散列码对应的桶中)。
访问顺序对于实现高速缓存的“最近最少使用”原则十分重要。
枚举集与映射
EnumSet是一个枚举类型元素集的高效实现。由于枚举类型只有有限个实例,所以EnumSet内部用位序列实现。如果对应的值在集中,则相应的位被置为1。
EnumMap是一个键类型为枚举类型的映射。他可以直接且高效地用一个值数组实现。
标识散列映射
类IdentityHashMap有特殊的作用。在这个类中,键的散列值不是用hashCode函数计算的,而是用System.identityHashCode方法计算的。这是Object.hashCode方法根据对象的内存地址类计算散列码所使用的方式。而且,在对两个对象进行比较时,IdentityHashMap类使用==,而不是用equals。
也就是说,不同的键对象,即使内容相同,也被视为是不同的对象。在实现对象遍历算法(如对象串行化)时,这个类非常有用,可以用来跟踪每个对象的遍历状况。
Java核心技术-映射的更多相关文章
- Java核心技术点之集合框架
1. 概述 Java集合框架由Java类库的一系列接口.抽象类以及具体实现类组成.我们这里所说的集合就是把一组对象组织到一起,然后再根据不同的需求操纵这些数据.集合类型就是容纳这些对象的一个容 ...
- java核心技术-(总结自杨晓峰-java核心技术36讲)
1. 谈谈你对java平台的理解 首先是java最显著的两个特性,一次写入处处运行:还有垃圾收集器gc,gc能够对java内存进行管理回收,程序员不需要关心内存的分配和回收问题 然后谈谈jre和jdk ...
- 《Java核心技术 卷II 高级特性(原书第9版)》
<Java核心技术 卷II 高级特性(原书第9版)> 基本信息 原书名:Core Java Volume II—Advanced Features(Ninth Edition) 作者: ( ...
- java核心技术卷一
java核心技术卷一 java基础类型 整型 数据类型 字节数 取值范围 int 4 +_2^4*8-1 short 2 +_2^2*8-1 long 8 +_2^8*8-1 byte 1 -128- ...
- Java 内存映射文件
import java.io.*; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import jav ...
- java核心技术(第十版卷一)笔记(纯干货!)
这是我读过的第三本关于java基础的书.第一本<<java从入门到精通>>这本书让我灵识初开.第二本<<java敏捷开发>>这本书则是有一次被一位师傅批 ...
- 2019 最新 Java 核心技术教程,都在这了!
Java技术栈 www.javastack.cn 优秀的Java技术公众号 以下是Java技术栈微信公众号发布的所有关于 Java 的技术干货,会从以下几个方面汇总,本文会长期更新. Java 基础篇 ...
- Java核心技术点之泛型
1. Why ——引入泛型机制的原因 假如我们想要实现一个String数组,并且要求它可以动态改变大小,这时我们都会想到用ArrayList来聚合String对象.然而,过了一阵,我们想要实现一个大小 ...
- Java核心技术点之内部类
1. 为什么要使用内部类 内部类就是定义在一个类内部的类,那么为什么要使用内部类呢?主要原因有以下几点:第一,内部类中定义的方法能访问到它所在外部类的私有属性及方法:第二,外部类无法实现对同一 ...
随机推荐
- 微信小程序:java后台获取openId
一.功能描述 openId是某个微信账户对应某个小程序或者公众号的唯一标识,但openId必须经过后台解密才能获取(之前实现过前台解密,可是由于微信小程序的种种限制,前台解密无法在小程序发布后使用) ...
- QT 遇到的问题
遇到的问题: 1:在QT中使用opengl,发现一个很神奇的问题,个人感觉是qt的bug. 问题详情:在我添加了一个成员变量之后,使用opengl编写的窗口没有任何输出了,只有一个背景. 但是删除那个 ...
- Js基础---红宝书读书日记(1)-------基本类型和引用类型
JS的变量可能包含两种不同数据类型的值,基本类型和引用类型; 基本类型是指简单的数据段,引用类型是指可能由多个值构成的对象; JS高级程序设计第三章介绍了变量分为 5种简单数据类型(string/nu ...
- @Pointcut的用法
在Spring 2.0中,Pointcut的定义包括两个部分:Pointcut表示式(expression)和Pointcut签名(signature).让我们先看看execution表示式的格式: ...
- 分布式监控系统Zabbix--完整安装记录-批量添加主机和自动发现端口
一.Zabbix-3.0.3批量添加主机的配置如下: 0)被监控机上要安装zabbix_agent,并配置好zabbix_agentd.conf (如下172.29.8.50是zabbix_serve ...
- Microsoft Visual Studio2013安装及单元测试
和大家分享一下我安装VS2013和单元测试的过程.VS是微软多种编程软件的集合,功能与工作环境更全面,相比VC++6.0来说是一个很大的提升. VS安装: VS的安装和普通软件相同,只是花费的时间很长 ...
- Individual P1: Summary
经过5个小时成功把simple mode写差不多了..orz 也是蛮拼的. 开始毫无头绪,本能地开始从度娘搜索‘c# 单词统计’= =看了两段代码也算是见过c#的人了.差不多花了我1小时的时间. 然后 ...
- Scrum Meeting day 3
第三次会议 No_00:工作情况 No_01:任务说明 待完成 已完成 No_10:燃尽图 No_11:照片记录 No_100:代码/文档签入记录
- Linux内核分析期中总结
目录: “Linux内核分析”实验一报告 “Linux内核分析”实验二报告 “Linux内核分析”实验三报告 Linux实验四报告 “Linux内核分析”第五周报告 "Linux内核分析&q ...
- Linux内核第四节 20135332武西垚
实验目的: 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 实验过程: 查看系统调用列表 get pid 函数 #include <stdio.h> #include & ...