`
flyingis
  • 浏览: 296675 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java容器分析--Map

阅读更多

    作者:Flyingis

标准的
Java类库中包含了几种类型的Map,它们都拥有同样的基本接口Map,但是行为特性各不相同,主要表现在效率、键值对的保存、元素呈现次序、对象的保存周期和判定键是否等价的策略等方面。<!----><o:p></o:p>

1.Map的功能方法<o:p></o:p>

Map(interface): 维护labelvalue的关联性,使得可以通过label查找value<o:p></o:p>

HashMap: Map基于散列表的实现,取代了Hashtable。插入和查询label/value的开销是固定的,并且可以通过构造器设置容量和负载因子,以调整容器的性能。<o:p></o:p>

LinkedHashMap: HashMap的基础上做了一些改进,在迭代遍历它时,取得label/value的顺序是其插入的次序,或者是最近最少使用(LRU)的次序,速度上比HashMap要慢一点,但在迭代访问时速度会更快,主要原因是它使用了链表维护内部次序。<o:p></o:p>

TreeMap: 查看labellabel/value时,元素会被排序,其次序由ComparableComparator决定,因此查询所得到的结果是经过排序的。另外,它是唯一带有subMap()方法的Map具体类,即返回一个子树。它也是SortedMap接口的唯一实现,subMap()方法也是从该接口继承的。<o:p></o:p>

WeakHashMap: Weak Key映射,允许释放映射所指向的对象。当映射之外没有引用指向某个label时,此label可以被垃圾收集器回收。<o:p></o:p>

IdentityHashMap: 使用==代替equals()label进行比较的散列映射。<o:p></o:p>

2.hashCode()<o:p></o:p>

         当使用标准库中的类Integer作为HashMaplabel时,程序能够正常运行,但是使用自己创建的类作为HashMaplabel时,通常犯一个错误。<o:p></o:p>

         HashMap中通过label查找value时,实际上是计算label对象地址的散列码来确定value的。一般情况下,我们是使用基类Object的方法hashCode()来生成散列码,它默认是使用对象的地址来计算的,因此由第一个对象new Apple(5)和第二个对象new Apple(5)生成的散列码是不同的,不能完成正确的查找。通常,我们可以编写自己的hashCode()方法来覆盖基类的原始方法,但与此同时,我们必须同时实现equals()方法来判断当前的label是否与表中存在的label相同。正确的equals()方法满足五个条件:<o:p></o:p>

(1)     自反性。对于任意的xx.equals(x)一定返回true<o:p></o:p>

(2)     对称性。对于任意的xy,如果y.equals(x)返回true,则x.equals(y)也返回true<o:p></o:p>

(3)     传递性。对于任意的xyz,如果有x.equals(y)返回truey.equals(z)返回true,则x.equals(z)一定返回true<o:p></o:p>

(4)     一致性。对于任意的xy,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false<o:p></o:p>

(5)     对任何不是nullxx.equals(null)一定返回false<o:p></o:p>

equals()比较的是对象的地址,如果要使用自己的类作为HashMaplabel,必须同时重载hashCode()equals()方法。<o:p></o:p>

使用散列的目的:想要使用一个对象来查找另一个对象。使用TreeSetTreeMap也能实现此目的。另外,还可以自己实现一个Map,此时,必须提供Map.entrySet()方法来生成Map.Entry对象的Set<o:p></o:p>

使用散列的价值:速度,散列使得查询可以快速进行。散列将label保存载数组中方便快速查询,因为存储一组元素最快的数据结构是数组,用它来表示label的信息(后面有信息的描述),而不是label本身。通过label对象计算得到一个数字,作为数组的下标,这个数字就是散列码(即前面所述的信息)。该散列码具体是通过定义在基类Object中,可能由程序员自定义的类覆盖的hashCode()方法,即散列函数生成。为了解决数组容量带来的限制,可以使不同的label生成相同的下标,保存在一个链表list中,每一个链表就是数组的一个元素。查询label时就可以通过对list中的信息进行查找,当散列函数比较好,数组的每个位置中的list长度较短,则可以快速查找到数组元素list中的某个位置,提高了整体速度。<o:p></o:p>

散列表中的slot通常称为bucket,为了使散列分步均匀,bucket的值一般取质数。但事实证明,质数实际上并不是散列bucket的理想容量,近来Java散列实现都使用2的幂,具体如何验证以后再续。<o:p></o:p>

3.HashMap的性能因子<o:p></o:p>

容量(capacity): 散列表中bucket的数量。<o:p></o:p>

初始化容量(initial capacity): 创建散列表时bucket的数量。可以在构造方法中指定HashMapHashSet的初始化容量。<o:p></o:p>

尺寸(size): 散列表中记录的数量。(数组的元素个数,非list中元素总和)<o:p></o:p>

负载因子(load factor): 尺寸/容量。负载因子为0,表示空的散列表,0.5表示半满的散列表。轻负载的散列表具有冲突少,适宜插入与查询的特点,但是使用迭代器遍历会比较慢。较高的负载会减少所需空间大小。当负载达到指定值时,容器会自动成倍地增加容量,并将原有的对象重新分配,存入新的bucket中,这个过程称为“重散列”。<o:p></o:p>

4.重写hashCode()的关键<o:p></o:p>

(1)     对同一个对象调用hashCode()都应该生成同样的值。<o:p></o:p>

(2)     hashCode()方法不要依赖于对象中易变的数据,当数据发生变化时,hashCode()就会生成一个不同的散列码,即产生了一个不同的label<o:p></o:p>

(3)     hashCode()不应依赖于具有唯一性的对象信息,例如对象地址。<o:p></o:p>

(4)     散列码应该更关心速度,而不是唯一性,因为散列码不必是唯一的。<o:p></o:p>

(5)     好的hashCode()应该产生分步均匀的散列码。在Effective Java(Addison-Wesley 2001)中,Joshua BlochhashCode()给出了设计指导,可以参考。<o:p></o:p>

编写正确高效的hashCode()equals()可以参考ApacheJakarta Commons项目中的工具。

其它相关内容:
Java容器分析--数组
Java容器分析--List和Set
分享到:
评论

相关推荐

    Java容器学习笔记:容器概览,容器中的设计模式,容器源码分析 - List,容器源码分析 - Map,容器源码分析 - 并发容

    Java容器学习笔记: 容器概览, 容器中的设计模式, 容器源码分析 - List, 容器源码分析 - Map, 容器源码分析 - 并发容 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,...

    java版list-map实现 树结构 父子结构 通俗易懂

    此java类实现了对数据表的分类递归树的实现,为本人倾力之作,后期,会发布js版,敬请期待!

    Java-concurrentMap-内存模型深入分析-HotCode

    总结来说,深入理解Java内存模型对于正确实现并发容器如`concurrentMap`至关重要。通过分析HotCode,我们可以找出并优化性能关键点。同时,熟悉`HashMap`的底层机制和使用注解技术可以增强代码的并发安全性。而了解...

    Crazy-JAVA-mind-map.zip_Crazy JAVA mind map_crazy_java-mindmap_m

    此外,容器和集合框架是Java编程中不可或缺的部分。ArrayList、LinkedList、HashMap等集合类提供了数据存储和操作的便利。同时,接口(如Comparator、Iterable)和设计模式(如工厂模式、单例模式)也是高级Java...

    java练习题--容器使用练习

    通过这些练习,你将巩固对Java容器的理解,提高代码编写效率,并为解决实际问题打下坚实基础。记得在实践中不断挑战自己,尝试不同的场景和数据结构,以便更好地掌握Java容器的精髓。祝你在学习过程中取得优异的成绩...

    java基础教程----精华版

    - **变量**:在Java中,变量是存储数据的容器,分为基本类型(如int, double, boolean等)和引用类型(如类、接口、数组)。 - **数据类型**:Java有两大类数据类型,即原始类型(primitives)和引用类型...

    java-8-openjdk-amd64

    OpenJDK是Java Development Kit(JDK)的一个实现,它提供了Java语言的编译器、调试器、性能分析工具以及运行时环境。这个特定的版本针对的是AMD64处理器架构,也被称为x86_64或x64架构,广泛应用于Linux操作系统。 ...

    Java-Interview-超全集合github上评分最高的jiva面试题

    - **并发容器**:如ConcurrentHashMap、BlockingQueue、ThreadPoolExecutor等在多线程环境下的应用。 4. **内存模型与垃圾回收** - **JVM内存结构**:堆、栈、方法区、本地方法栈等区域的划分和作用。 - **垃圾...

    java容器详细解析

    Java容器主要分为两大类:Collection和Map。 Collection Collection是一个独立元素的序列,这些元素都服从一条或多条规则。Collection接口提供了基本的操作方法,例如add、remove、contains等。 List List是一个...

    cors-filter-1.7&java;-property-utils-1.9

    Tomcat是Apache软件基金会的开源Java Servlet容器,用于运行Java Web应用程序,包括JSP和Servlet。在部署Geoserver时,我们需要将`geoserver.war`文件放到Tomcat的`webapps`目录下,Tomcat会自动解压并运行这个WAR...

    java容器学习心得

    ### Java容器学习心得详解 在Java编程中,容器(Containers)是存储和操作对象集合的重要工具,主要包括集合(Collections)和映射(Maps)。本文将深入解析Java容器的关键概念、特性以及不同容器类型的应用场景。 ...

    java-1.8.0-openjdk-1.8.0.201-2.b09.redhat.windows.x86_64.zip

    5. **Optional类**:为了解决空指针异常问题,Java 8引入了`Optional`类,它是一个容器对象,可能包含或不包含非null值。这有助于开发者编写更清晰、更安全的代码,避免出现`NullPointerException`。 6. ** Nashorn...

    JAVA容器对象整理

    这些知识点仅仅是Java容器对象的一部分,实际的博客可能会包含更多细节,如源码分析、性能对比和最佳实践。通过阅读博客中的`持有对象.xmind`文件,可以进一步了解博主对这些概念的详细整理和分类。如果你对Java容器...

    JAVA程序员必读--基础篇

    此外,Java集合框架是另一个关键部分,包括List、Set和Map接口,以及ArrayList、LinkedList、HashSet、HashMap等实现。这些集合类提供了存储和操作对象的方式。 在面向对象编程方面,你会学习类的定义、继承、封装...

    JAVA程序员必读--基础篇chm

    8. **集合框架**:Java集合框架包括List、Set、Map等接口和ArrayList、LinkedList、HashSet、HashMap等实现类。它们提供了存储和操作对象的容器,是Java编程中不可或缺的一部分。 9. **输入/输出流**:Java的IO流...

    java容器源码-Java-basic-notes-sourcecode:学习Java以来​​的基本入门源代码,包括基本语法,数据类型,分支语

    Java容器源码分析 在Java编程中,容器是管理和组织对象的重要工具,它们提供了一种方式来存储和操作一组相关的对象。本项目"Java-basic-notes-sourcecode"包含了学习Java基础知识时涉及的一些源代码示例,涵盖了从...

    JAVA容器的概述,List,Map,Set

    JAVA容器的概述,List,Map,Set

    java JDK1.5---32位和64位

    6. **类型安全的异构容器(Collections Framework Enhancements)**:对集合框架进行了增强,如加入了`List`, `Set`, `Map`接口的`addAll()`、`containsAll()`、`removeAll()`和`retainAll()`方法,以及`Collections...

Global site tag (gtag.js) - Google Analytics