MAP 大概介绍

本文深入探讨了Java中的Map接口及其多种实现方式,包括通用Map和专用Map。重点介绍了哈希映射技术,解释了哈希函数如何工作以及如何处理冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

核心 Map

Java 自带了各种 Map 类。 这些 Map 类可归为三种类型:

  1. 通用 Map,用于在应用程序中管理映射,通常在 java.util 程序包中实现
    • HashMap
    • Hashtable
    • Properties
    • LinkedHashMap
    • IdentityHashMap
    • TreeMap
    • WeakHashMap
    • ConcurrentHashMap
  2. 专用 Map,您通常不必亲自创建此类 Map,而是通过某些其他类对其进行访问
    • java.util.jar.Attributes
    • javax.print.attribute.standard.PrinterStateReasons
    • java.security.Provider
    • java.awt.RenderingHints
    • javax.swing.UIDefaults
  3. 一个用于帮助实现您自己的 Map 类的抽象类
    • AbstractMap

内部哈希: 哈希映射技术

几乎所有通用 Map 都使用哈希映射。 这是一种将元素映射到数组的非常简单的机制,您应了解哈希映射的工作原理,以便充分利用 Map。

哈希映射结构由一个存储元素的内部数组组成。 由于内部采用数组存储,因此必然存在一个用于确定任意键访问数组的索引机制。 实际上,该机制需要提供一个小于数组大小的整数索引值。 该机制称作哈希函数。 在 Java 基于哈希的 Map 中,哈希函数将对象转换为一个适合内部数组的整数。 您不必为寻找一个易于使用的哈希函数而大伤脑筋: 每个对象都包含一个返回整数值的 hashCode() 方法。 要将该值映射到数组,只需将其转换为一个正值,然后在将该值除以数组大小后取余数即可。 以下是一个简单的、适用于任何对象的 Java 哈希函数

int hashvalue = Maths.abs(key.hashCode()) % table.length;

(% 二进制运算符(称作模)将左侧的值除以右侧的值,然后返回整数形式的余数。)

实际上,在 1.4 版发布之前,这就是各种基于哈希的 Map 类所使用的哈希函数。 但如果您查看一下代码,您将看到

int hashvalue = (key.hashCode() & 0x7FFFFFFF) % table.length;

它实际上是使用更快机制获取正值的同一函数。 在 1.4 版中,HashMap 类实现使用一个不同且更复杂的哈希函数,该函数基于 Doug Lea 的 util.concurrent 程序包(稍后我将更详细地再次介绍 Doug Lea 的类)。

图 3: 哈希工作原理

该图介绍了哈希映射的基本原理,但我们还没有对其进行详细介绍。 我们的哈希函数将任意对象映射到一个数组位置,但如果两个不同的键映射到相同的位置,情况将会如何? 这是一种必然发生的情况。 在哈希映射的术语中,这称作冲突。 Map 处理这些冲突的方法是在索引位置处插入一个链接列表,并简单地将元素添加到此链接列表。 因此,一个基于哈希的 Map 的基本 put() 方法可能如下所示

public Object put(Object key, Object value) {
  //我们的内部数组是一个 Entry 对象数组
  //Entry[] table;

  //获取哈希码,并映射到一个索引
  int hash = key.hashCode();
  int index = (hash & 0x7FFFFFFF) % table.length;

  //循环遍历位于 table[index] 处的链接列表,以查明
  //我们是否拥有此键项 — 如果拥有,则覆盖它
  for (Entry e = table[index] ; e != null ; e = e.next) {
    //必须检查键是否相等,原因是不同的键对象
    //可能拥有相同的哈希
    if ((e.hash == hash) && e.key.equals(key)) {
      //这是相同键,覆盖该值
      //并从该方法返回 old 值
      Object old = e.value;
      e.value = value;
      return old;
    }
  }

  //仍然在此处,因此它是一个新键,只需添加一个新 Entry
  //Entry 对象包含 key 对象、 value 对象、一个整型的 hash、
  //和一个指向列表中的下一个 Entry 的 next Entry

  //创建一个指向上一个列表开头的新 Entry,
  //并将此新 Entry 插入表中
  Entry e = new Entry(hash, key, value, table[index]);
  table[index] = e;

  return null;
}

如果看一下各种基于哈希的 Map 的源代码,您将发现这基本上就是它们的工作原理。 此外,还有一些需要进一步考虑的事项,如处理空键和值以及调整内部数组。 此处定义的 put() 方法还包含相应 get() 的算法,这是因为插入包括搜索映射索引处的项以查明该键是否已经存在。 (即 get() 方法与 put() 方法具有相同的算法,但 get() 不包含插入和覆盖代码。) 使用链接列表并不是解决冲突的唯一方法,某些哈希映射使用另一种“开放式寻址”方案,本文对其不予介绍。

优化 Hasmap

如果哈希映射的内部数组只包含一个元素,则所有项将映射到此数组位置,从而构成一个较长的链接列表。 由于我们的更新和访问使用了对链接列表的线性

<think>嗯,用户想了解map函数的用法和示例代码。首先,我得回忆一下Python中的map函数是什么。记得map是一个内置函数,用来对可迭代对象的每个元素应用指定的函数,然后返回一个迭代器。用户可能已经知道一些基本概念,但需要具体的说明和例子。 接下来,我需要整理map函数的基本用法。根据引用[1]和[2],基本语法是map(function, iterable)。要举一个简单的例子,比如把列表中的每个元素平方,可以用lambda函数配合map。示例代码应该是这样的:map(lambda x: x**2, [1,2,3]),然后转换成列表。不过得注意,在Python 3中,map返回的是迭代器,必须转成列表才能看到结果。 然后是多参数处理的情况。用户可能想知道如果有多个可迭代对象怎么办。比如同时处理两个列表的相加,这时候需要用到多个iterable参数。例如,map(lambda x,y: x+y, [1,2], [3,4]),结果应该是[4,6]。这里要说明函数需要接收相应数量的参数,并且如果长度不同,会以最短的为准。 接下来是数据类型转换的应用场景。比如将字符串列表转成整数,可以用map(int, ["1","2","3"])。这也是常见的用法,用户可能在实际数据处理中用到。 还需要提到与其他函数式编程工具的对比,比如列表推导式。虽然列表推导式更简洁,但map可能在处理复杂函数时更有优势,或者与lambda结合更灵活。不过要指出两者可以互换,取决于个人习惯。 另外,引用[3]提到了TensorFlow的tf.map_fn,虽然用户主要问的是Python内置的map,但可能需要说明一下区别,比如tf.map_fn用于张量的并行处理,适用于深度学习框架中的计算图环境。不过如果用户没有提到TensorFlow,可能不需要深入,但作为相关知识可以简要提及。 用户可能需要示例代码来更好地理解。要确保每个例子都清晰,比如基本用法、多参数、类型转换,以及结合lambda和自定义函数的情况。比如定义一个自定义函数double,然后用map应用它。 还要注意常见误区,比如忘记将map结果转换为列表,导致得到的是一个迭代器对象。此外,处理多参数时函数的参数数量必须和iterable的数量一致,否则会出错。 最后,生成相关问题时要考虑用户可能进一步想了解的内容,比如map与列表推导式的比较,异常处理,惰性求值的优势,或者在其他库中的应用如Pandas的map方法。这些问题可以帮助用户深入学习和解决问题。</think>### Map函数使用说明及示例 #### 一、基本定义 `map()` 是 Python 的内置函数,用于对可迭代对象(如列表、元组)中的每个元素应用指定函数,返回一个包含计算结果的新迭代器[^2]。其语法为: $$ \text{map}(function, iterable) $$ #### 二、核心功能 1. **单参数处理** 将函数作用于单个可迭代对象的每个元素: ```python # 示例:平方运算 numbers = [1, 2, 3] squared = map(lambda x: x**2, numbers) print(list(squared)) # 输出 [1, 4, 9] ``` 2. **多参数处理** 支持同时操作多个可迭代对象(函数需接收对应数量的参数): ```python # 示例:两数相加 list1 = [1, 2] list2 = [3, 4] result = map(lambda x, y: x + y, list1, list2) print(list(result)) # 输出 [4, 6] ``` 3. **数据类型转换** 常用于批量转换数据类型: ```python # 示例:字符串转整数 str_list = ["1", "2", "3"] int_list = list(map(int, str_list)) # 输出 [1, 2, 3] ``` #### 三、进阶用法 1. **与高阶函数结合** 可配合自定义函数使用: ```python def double(x): return x * 2 print(list(map(double, [5, 10]))) # 输出 [10, 20] ``` 2. **惰性求值特性** 返回的迭代器仅在需要时计算元素,适合处理大型数据集。 #### 四、对比其他工具 | 方法 | 特点 | 适用场景 | |---------------|------------------------------|-----------------------| | `map()` | 函数式编程风格,惰性求值 | 批量数据转换、并行处理 | | 列表推导式 | 语法简洁,直接生成列表 | 简单逻辑处理 | #### 五、TensorFlow扩展 在深度学习框架中,`tf.map_fn()` 提供张量级别的并行映射,支持计算图优化[^3]: ```python import tensorflow as tf inputs = tf.constant([[1, 2], [3, 4]]) outputs = tf.map_fn(lambda x: x * 2, inputs) # 输出 [[2,4], [6,8]] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值