WEB开发网      婵犵數濮烽弫鍛婄箾閳ь剚绻涙担鍐叉搐绾剧懓鈹戦悩瀹犲闁汇倗鍋撻妵鍕箛閸洘顎嶉梺绋款儑閸犳劙濡甸崟顖氬唨闁靛ě浣插亾閹烘鈷掗柛鏇ㄥ亜椤忣參鏌″畝瀣暠閾伙絽銆掑鐓庣仭缁楁垿姊绘担绛嬪殭婵﹫绠撻、姘愁樄婵犫偓娴g硶鏀介柣妯款嚋瀹搞儱螖閻樺弶鍟炵紒鍌氱Ч瀹曟粏顦寸痪鎯с偢瀵爼宕煎☉妯侯瀳缂備焦顨嗗畝鎼佸蓟閻旈鏆嬮柣妤€鐗嗗▓妤呮⒑鐠団€虫灀闁哄懐濮撮悾鐤亹閹烘繃鏅濋梺闈涚墕濡瑩顢欒箛鏃傜瘈闁汇垽娼ф禒锕傛煕閵娿儳鍩f鐐村姍楠炴﹢顢欓懖鈺嬬幢闂備浇顫夊畷妯肩矓椤旇¥浜归柟鐑樻尭娴滃綊姊虹紒妯虹仸闁挎洍鏅涜灋闁告洦鍨遍埛鎴︽煙閼测晛浠滃┑鈥炽偢閹鈽夐幒鎾寸彇缂備緡鍠栭鍛搭敇閸忕厧绶炴俊顖滅帛濞呭洭姊绘担鐟邦嚋缂佽鍊垮缁樼節閸ャ劍娅囬梺绋挎湰缁嬫捇宕㈤悽鍛婄厽閹兼番鍨婚埊鏇㈡煥濮樿埖鐓熼煫鍥ュ劤缁嬭崵绱掔紒妯肩畺缂佺粯绻堝畷姗€濡歌缁辨繈姊绘担绛嬪殐闁搞劋鍗冲畷顖炲级閹寸姵娈鹃梺缁樻⒒閳峰牓寮崒鐐寸厱闁抽敮鍋撻柡鍛懅濡叉劕螣鐞涒剝鏂€闂佺粯鍔曞Ο濠囧吹閻斿皝鏀芥い鏃囨閸斻倝鎽堕悙鐑樼厱闁哄洢鍔屾晶顖炴煕濞嗗繒绠婚柡灞界Ч瀹曨偊宕熼鈧▍锝囩磽娴f彃浜炬繝銏f硾椤戝洨绮绘ィ鍐╃厵閻庢稒岣跨粻姗€鏌ㄥ☉妯夹fい銊e劦閹瑩顢旈崟顓濈礄闂備浇顕栭崰鏍礊婵犲倻鏆﹂柟顖炲亰濡茶鈹戦埄鍐ㄧ祷妞ゎ厾鍏樺璇测槈閵忕姈鈺呮煏婢跺牆鍔撮柛鏂款槺缁辨挻鎷呯粙搴撳亾閸濄儳鐭撶憸鐗堝笒閺嬩線鏌熼崜褏甯涢柡鍛倐閺屻劑鎮ら崒娑橆伓 ---闂傚倸鍊搁崐鐑芥倿閿旈敮鍋撶粭娑樺幘濞差亜鐓涢柛娑卞幘椤斿棝姊虹捄銊ユ珢闁瑰嚖鎷�
开发学院WEB开发Jsp Java Map 集合类简介 阅读

Java Map 集合类简介

 2008-01-05 20:38:35 来源:WEB开发网 闂傚倸鍊搁崐椋庢濮橆兗缂氱憸宥堢亱闂佸湱铏庨崰鏍不椤栫偞鐓ラ柣鏇炲€圭€氾拷闂傚倸鍊搁崐椋庣矆娓氣偓楠炲鏁撻悩鎻掔€梺姹囧灩閻忔艾鐣烽弻銉︾厵闁规鍠栭。濂告煕鎼达紕校闁靛洤瀚伴獮鎺楀箣濠靛啫浜鹃柣銏⑶圭壕濠氭煙閻愵剚鐏辨俊鎻掔墛缁绘盯宕卞Δ鍐冣剝绻涘畝濠佺敖缂佽鲸鎹囧畷鎺戭潩閹典焦鐎搁梻浣烘嚀閸ゆ牠骞忛敓锟�婵犵數濮烽弫鍛婃叏椤撱垹绠柛鎰靛枛瀹告繃銇勯幘瀵哥畼闁硅娲熷缁樼瑹閳ь剙岣胯鐓ら柕鍫濇偪濞差亜惟闁宠桨鑳堕崝锕€顪冮妶鍡楃瑐闁煎啿鐖奸崺濠囧即閵忥紕鍘梺鎼炲劗閺呮稒绂掕缁辨帗娼忛埡浣锋闂佽桨鐒﹂幑鍥极閹剧粯鏅搁柨鐕傛嫹闂傚倸鍊搁崐椋庢濮橆兗缂氱憸宥堢亱闂佸湱铏庨崰鏍不椤栫偞鐓ラ柣鏇炲€圭€氾拷  闂傚倸鍊搁崐鐑芥嚄閼哥數浠氱紓鍌欒兌缁垶銆冮崨鏉戠厺鐎广儱顦崡鎶芥煏韫囨洖校闁诲寒鍓熷铏圭磼濡搫顫嶅銈嗗姉閸樠囧煡婢跺á鐔兼煥鐎n兘鍋撴繝姘拺鐟滅増甯掓禍浼存煕閹惧鈽夐柍缁樻煥椤繈鎳滅喊妯诲闂備礁鎲$粙鎴︺偑閺夋垟鏋旈柡鍐e亾缂佺粯绋撴禒锕傚磼濮橆剦鐎抽梻浣哥-缁垶骞戦崶顒傚祦閻庯綆浜栭弨浠嬫煙闁箑澧い鏂垮€规穱濠囨倷椤忓嫧鍋撻弽褜娼栧┑鐘宠壘閸屻劎鎲歌箛娑樼疅闁圭虎鍠楅弲鎼佹煥閻曞倹瀚�
核心提示:java.util 中的集合类包含 Java 中某些最常用的类, 最常用的集合类是 List 和 Map,Java Map 集合类简介, List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,您将看到 int hashvalue = (key.hashCode() & 0x7FFFFFF

  java.util 中的集合类包含 Java 中某些最常用的类。 最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。

Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。 从概念上而言,您可以将 List 看作是具有数值键的 Map。 而实际上,除了 List 和 Map 都在定义 java.util 中外,两者并没有直接的联系。本文将着重介绍核心 Java 发行套件中附带的 Map,同时还将介绍如何采用或实现更适用于您应用程序特定数据的专用 Map。

了解 Map 接口和方法

Java 核心类中有很多预定义的 Map 类。 在介绍具体实现之前,我们先介绍一下 Map 接口本身,以便了解所有实现的共同点。 Map 接口定义了四种类型的方法,每个 Map 都包含这些方法。 下面,我们从两个普通的方法(表 1)开始对这些方法加以介绍。

表 1: 覆盖的方法。 我们将这 Object 的这两个方法覆盖,以正确比较 Map 对象的等价性。 equals(Object o) 比较指定对象与此 Map 的等价性
hashCode() 返回此 Map 的哈希码



Map 构建

Map 定义了几个用于插入和删除元素的变换方法(表 2)。

表 2: Map 更新方法: 可以更改 Map 内容。 clear() 从 Map 中删除所有映射
remove(Object key) 从 Map 中删除键和关联的值
put(Object key, Object value) 将指定值与指定键相关联
clear() 从 Map 中删除所有映射
putAll(Map t) 将指定 Map 中的所有映射复制到此 map



尽管您可能注重到,纵然假设忽略构建一个需要传递给 putAll() 的 Map 的开销,使用 putAll() 通常也并不比使用大量的 put() 调用更有效率,但 putAll() 的存在一点也不稀奇。 这是因为,putAll() 除了迭代 put() 所执行的将每个键值对添加到 Map 的算法以外,还需要迭代所传递的 Map 的元素。 但应注重,putAll() 在添加所有元素之前可以正确调整 Map 的大小,因此假如您未亲自调整 Map 的大小(我们将对此进行简单介绍),则 putAll() 可能比预期的更有效。

查看 Map

迭代 Map 中的元素不存在直接了当的方法。 假如要查询某个 Map 以了解其哪些元素满足特定查询,或假如要迭代其所有元素(无论原因如何),则您首先需要获取该 Map 的“视图”。 有三种可能的视图(参见表 3)

所有键值对 — 参见 entrySet()
所有键 — 参见 keySet()
所有值 — 参见 values()

前两个视图均返回 Set 对象,第三个视图返回 Collection 对象。 就这两种情况而言,问题到这里并没有结束,这是因为您无法直接迭代 Collection 对象或 Set 对象。要进行迭代,您必须获得一个 Iterator 对象。 因此,要迭代 Map 的元素,必须进行比较烦琐的编码


Iterator keyValuePairs = aMap.entrySet().iterator();
Iterator keys = aMap.keySet().iterator();
Iterator values = aMap.values().iterator();


值得注重的是,这些对象(Set、Collection 和 Iterator)实际上是基础 Map 的视图,而不是包含所有元素的副本。 这使它们的使用效率很高。 另一方面,Collection 或 Set 对象的 toArray() 方法却创建包含 Map 所有元素的数组对象,因此除了确实需要使用数组中元素的情形外,其效率并不高。

我运行了一个小测试(随附文件中的 Test1),该测试使用了 HashMap,并使用以下两种方法对迭代 Map 元素的开销进行了比较:


int mapsize = aMap.size();

Iterator keyValuePairs1 = aMap.entrySet().iterator();
for (int i = 0; i < mapsize; i++)
{
Map.Entry entry = (Map.Entry) keyValuePairs1.next();
Object key = entry.getKey();
Object value = entry.getValue();
...
}

Object[] keyValuePairs2 = aMap.entrySet().toArray();
for (int i = 0; i < rem; i++) {
{
Map.Entry entry = (Map.Entry) keyValuePairs2[i];
Object key = entry.getKey();


Object value = entry.getValue();
...
}


此测试使用了两种测量方法: 一种是测量迭代元素的时间,另一种测量使用 toArray 调用创建数组的其他开销。 第一种方法(忽略创建数组所需的时间)表明,使用已从 toArray 调用中创建的数组迭代元素的速度要比使用 Iterator 的速度大约快 30%-60%。 但假如将使用 toArray 方法创建数组的开销包含在内,则使用 Iterator 实际上要快 10%-20%。 因此,假如由于某种原因要创建一个集合元素的数组而非迭代这些元素,则应使用该数组迭代元素。 但假如您不需要此中间数组,则不要创建它,而是使用 Iterator 迭代元素。

表 3: 返回视图的 Map 方法: 使用这些方法返回的对象,您可以遍历 Map 的元素,还可以删除 Map 中的元素。 entrySet() 返回 Map 中所包含映射的 Set 视图。 Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素

keySet() 返回 Map 中所包含键的 Set 视图。 删除 Set 中的元素还将删除 Map 中相应的映射(键和值)
values() 返回 map 中所包含值的 Collection 视图。 删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)



访问元素

表 4 中列出了 Map 访问方法。Map 通常适合按键(而非按值)进行访问。 Map 定义中没有规定这肯定是真的,但通常您可以期望这是真的。 例如,您可以期望 containsKey() 方法与 get() 方法一样快。 另一方面,containsValue() 方法很可能需要扫描 Map 中的值,因此它的速度可能比较慢。

表 4: Map 访问和测试方法: 这些方法检索有关 Map 内容的信息但不更改 Map 内容。 get(Object key) 返回与指定键关联的值
containsKey(Object key) 假如 Map 包含指定键的映射,则返回 true
containsValue(Object value) 假如此 Map 将一个或多个键映射到指定值,则返回 true
isEmpty() 假如 Map 不包含键-值映射,则返回 true
size() 返回 Map 中的键-值映射的数目



对使用 containsKey() 和 containsValue() 遍历 HashMap 中所有元素所需时间的测试表明,containsValue() 所需的时间要长很多。 实际上要长几个数量级! (参见图 1 和图 2,以及随附文件中的 Test2)。 因此,假如 containsValue() 是应用程序中的性能问题,它将很快显现出来,并可以通过监测您的应用程序轻松地将其识别。 这种情况下,我相信您能够想出一个有效的替换方法来实现 containsValue() 提供的等效功能。 但假如想不出办法,则一个可行的解决方案是再创建一个 Map,并将第一个 Map 的所有值作为键。 这样,第一个 Map 上的 containsValue() 将成为第二个 Map 上更有效的 containsKey()。


图 1: 使用 JDeveloper 创建并运行 Map 测试类




图 2: 在 JDeveloper 中使用执行监测器进行的性能监测查出应用程序中的瓶颈



核心 Map

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


通用 Map,用于在应用程序中治理映射,通常在 java.util 程序包中实现
HashMap
Hashtable
PRoperties
LinkedHashMap
IdentityHashMap
TreeMap
WeakHashMap
ConcurrentHashMap
专用 Map,您通常不必亲自创建此类 Map,而是通过某些其他类对其进行访问
java.util.jar.Attributes
javax.print.attribute.standard.PrinterStateReasons
java.security.Provider
java.awt.RenderingHints
javax.swing.UIDefaults
一个用于帮助实现您自己的 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 类实现使用一个不同且更复杂的哈希函数,该函数基于

Tags:Java Map 集合

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接