java学习之map,queue

来源:互联网 发布:淘宝真假客服 编辑:程序博客网 时间:2024/05/04 01:21

转自http://www.cnblogs.com/yanspecial/p/5611542.html

1.3、Map

    Map可以将对象映射到其他对象。

    映射表(也称为关联数组)的基本思想是它维护的是键-值(对)关联,因此可以使用键来查找值。

    标准的JAVA类库中包含以下实现:HashMap、TreeMap、LinkedHashMap、WeakHashMap、ConcurrentHashMap、IdentityHashMap等。他们的基类接口是一样的(Map),但是行为特性各不相同,比如效率、键值对的保持及呈现次序、对象的保持周期、映射表如何在多线程程序中工作和判定“键”等价的策略等。

    Map中key的使用与对Set中的元素要求一样,任何键都必须有一个eauals()方法。如果键被用于散列Map,则还必须具有恰当的hashCode()方法。如果键被用于TreeMap,它必须实现Compareble。

     性能

    在映射表中使用get()方法做线性搜索时,执行速度会很慢,儿使用HashMap可以提高速度。HashMap使用散列码,HashMap使用hashCode()进行快速查询。如果对速度还有更高的需求,可以自己创建Map的实现,并移除泛型支持等。

    HashMap

    基于散列表实现(取代HashTable)。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量和负载因子,以调整容器性能。

    如果没有其他限制,这应该是我们首选的实现方式,因为它对速度做了优化。其他实现有更多增强型特性,所以速度上回有取舍。

    LinkedHashMap

    类似于HashMap,但是迭代访问时,取得的“键值对”的顺序就是插入的顺序,或者是最近最少使用(LRU)的次序。比HashMap稍慢。在使用迭代器访问时,有更快的速度,因为内部使用链表维护次序。

    为提高速度,LinkedHashMap散列化所有的元素,但是在遍历键值对时,却又以元素的插入顺序返回键值对。

    可以在构造器中设定LinkedHashMap,使之采用LRU(最近最少使用)算法,所以没有被访问的元素就会出现在队列的前面。对于需要定期清理元素节约空间的程序来说,这个功能就能使程序和容易实现。

    TreeMap

    基于红黑树的实现。查看“键”或“值”时,他们会被排序(具体次序有比较函数决定)。TreeMap特点在于,所得到的结果都是经过排序的。TreeMap是唯一带有subMap()方法的Map,可以返回一个子树。

    WeakHashMap

    弱键映射,允许释放映射所指向的对象。是为了一些特殊的问题设计的。如果映射之外没有引用指向某个“键”,这个键就可以被垃圾回收器回收。

    ConcurrentHashMap

    一种线程安全的Map,不涉及同步锁。

    IdentityHashMap

    使用==代替equals()对键进行比较的散列映射。也是为解决特殊问题设计的。

    SortedMap

    TreeMap是目前SortedMap的一种实现方式,可以确保键处于排序状态。

    

 

 

1.4、QUEUE

 

 

1.5、迭代器

    迭代器

    一种设计模式,在这里是一个对象。功能是遍历并选择序列中的对象。java中的迭代器只能单向移动:

  •     1、使用方法iterator使容器返回一个Iterator,Iterator会准备好返回序列的第一个元素。
  •     2、使用next()获得序列的下一个元素
  •     3、使用hasNext()判断是否还有元素
  •     4、使用remove()将迭代器新近返回的元素删除

 

 

1.6、散列与散列码

    标准类库中的类可以被用作HashMap的键,因为他们具备了键所需的全部性质。

    当我们自己创建用作HashMap的键的类时,就必须在其中添加必要的方法。

    我们创建的类,默认会继承Object类,Object的hashCode()方法生成的散列码默认使用的是对象的地址来计算散列码。所以,试过仅仅是编写一个普通类,是不能用于HashMap的键的,首先要编写恰当的hashCode方法的覆盖版本。而仅仅是这样,依然不能工作,我们还需要编写eauals()方法,它也是Object的一部分。HashMap使用equals()方法判断当前的键是否与表中存在的键相同,默认的equals()方法同样是比较的对象的地址。

    正确的equals()方法必须满足下面的5个条件:

  1.     自反性:对任意的x,x.equals(x)一定成立
  2.     对称性:
  3.     传递性:
  4.     一致性:
  5.     对任何不为null的x,x.equals(null)一定返回false。

    如果不为键覆盖hashCode()和equals()方法,在使用散列的数据结构时就不能正确处理这个键。

    hashCode()

    首先,使用散列的目的在于:想要使用一个对象来查找另外一个对象。但是使用TreeMap或者自己实现Map也能达到目的(比如使用两个ArrayList分别存放key和值就能很容易的实现一个Map)。

    所以创建一个新的Map并不困难,但是,我们设计的时候,首先就应该考虑到速度问题,散列的价值就在于速度:散列可以得到一个非常快速的查询速度。

    查询的速度主要取决于key的查找,其中一种方法就是保持键的排序状态,然后使用二叉搜索树进行查询。

    但是散列是一种更优的方式,它将key存储在没某个地方以便于能过快速找到。存储一组元素(key的相关信息)最快的是数组,但是数组不能调整容量,这将是一个很大的限制。然后,可以如下设计:数组并不保存key本身,我们通过对象生成一个数字,将其作为数组的下标。儿这个数字就是散列码,由定义在Object或者由其子类覆盖的hashCode()方法生成(散列函数)。而由于数组的容量被固定了,不同的键也可能产生相同的下标(即产生冲突),所以数组有多大就不重要了,只要任何键都能在数组中找到它的位置。

    于是查询一个值的过程首先就是计算散列码,然后使用散列码查询数组。

    如果有没有冲突的查询过程,那就是有一个完美的散列函数,但这毕竟是特例。通常,冲突由外部链接处理:数组不直接保存值,二十保存值的list。然后使用eauals()方法对list中的值进行线性查找(其中较慢的一部分)。如果散列函数比较好,数组的每个位置都只有少量的值,因此查找的时候不是针对整个list,而是快速跳到数组的某个位置,只对很少的元素进行比较。所以HashMap就会如此快。

    下面我们来简单实现一个散列Map:

 

 

    由于散列表中的槽位通常称为桶位,因此我们将表示实际散列表的数组命名为为bucket。为师散列分布均匀,同的数量通常使用质数(其实,质数并不是散列桶的理想同期,java的散列函数都使用2的整数次方,除法和求余数是最慢的操作,详情请查阅更多相关资料)。

    经过以上的介绍,这里就探讨如何编写自己的hashCode()方法。

    设计hashCode()应该保证,无论何时调用同一个对象的hashCode()都能生成相同的值。而且也不应该使用具有唯一性的对象信息,如this的值,这可能会产生一个很糟糕的hashCode()。

    《effective java programming language guide》中给出了一些hashCode()的基本指导:

    1、给int变量result赋予某个非零值常量

    2、为对象内每个有意义的域f(每个可以做equals()操作的域)计算出一个int散列码c

    3、合并计算得到的散列码

    4、返回result

    5、检查hashCode()最后生成的结果,确保相同的对象有相同的散列码。

    根据以上指导实现的hashCode()的一个例子:

    

 

 

 

1.7、小结

    Java中提供的其实只有4中容器:Map、List、Set和Queue。

    Java提供了大量的持有对象方式:

    1、数组将数字与对象联系起来。它保存类型明确的对象,查询对象是,不需要对结果做类型转换。他可以是多维的,可以保存基本类型的数据。但是,数组一旦生成,其容量就不能改变。

    2、Collection保存单一的元素,而Map保存相关联的键值对。有了Java的泛型,就可以指定容器中存放的对象类型,因此就不会将错误类型的对象防止到容器中,而且在容器中获取元素时,不必进行类型转换。各种Collection和Map都可以在向其中添加更多的元素时,自动调整其尺寸。容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有的包装器类型之间的双向转换。

    3、像数组一样,List也建立数字索引与对象的关联,因此,数组和List都是排序好的容器。List能够自动扩充容量。

    4、如果要进行大量的随机访问,就是用ArrayList。如果要经常从表中间插入或删除元素,则应该使用LinkedList。

    5、各种Queue以及栈的行为,有LinkedList提供支持。

    6、Map是一种将对象与对象相关联的设计。HashMap设计用来快速访问TreeMap保存“键”始终处于排序状态(没有HashMap快);LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。

    7、Set不接受重复元素。HashSet提供最快的查询速度,TreeSet保持元素处于排序状态。LinkedHashSet以出入顺序保存元素。

0 0