java学习实录----集合理论(2)

2)Queue (队列)

  本来是单独的一类,不过在SUN的JDK里就是用LinkedList来提供这个功能的,主要方法是offer/pull/peek,因此归到这里。实现类LinkedList也实现了该接口,因为Queue经常要进行添加和删除操作,而LinkedList在这方面效率比较高。

队列是特殊的线性表,队列限制对线性表的访问方式: 队尾添加(offer)元素,队头取出(poll)元素。 队列遵循先进先出(FIFO  

first  Input First Output)的原则

队列提供了增删查方法也就是offer(E e),peek(), 和poll(); 返回值分别为boolean,删除的元素,查看的元素(一般也就是泛型)。 

几种特殊的队列

Deque(双端队列)Deque是Queue的子接口,定义了所谓的”双端队列”,可以从队首队尾进出。区别队列的方法也就是增加首尾标

志,比如offer(),变成 offerFirst(E e),和offerList(E e),分别是队首队尾。

 Stack(栈),使用双端队列,来禁止队尾的操作,只对队首进行操作提供方法也就是限制方法只从队首进出,push(E e): 表示从栈的顶部进入 E pop():表示从栈的顶部移除元素

2)Set

    Set集合中的元素是无序的(取出的顺序与存入的顺序无关)

    Set集合中的元素不能重复(即不能把同样的东西两次放入同一个Set容器中)

   a)实现类HashSet和TreeSet。

   -------- HashSet:底层数据结构是哈希表。是线程不安全的。不同步。

    HashSet是如何保证元素唯一性的呢?是通过元素的两个方法,hashCode和equals来完成。如果元素的HashCode值相

同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。

    当向Set容器中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hash值,然后根据 hash值决定该

对象在Set容器中的存储位置。如果两个元素的equals()方法返回 true,但它们的hashCode()方法返回值不相

等,hashSet 将会把它们存储在不同的位置。

                LinkedHashSet

        LinkedHashSet 是 HashSet 的子类。和HashSet一样LinkedHashSet也是不允许元素重复,LinkedHashSet 集合也是根据元

素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素是以插入顺序保存的。当然因为引用

了链表所以相对于HashSet ,LinkedHashSet 性能插入性能略较差,遍历能力较强。

    -------- TreeSet:底层数据结构是哈希表。是线程不安全的。不同步。

         TreeSet 是 SortedSet 接口的实现类,同样的,TreeSet也可以保证元素唯一,不过它是以compareTo或者compare方法来

保证元素的唯一性,TreeSet容器实际上是用于对存储元素进行排序,因为其元素是由二叉树形式储存的。

3.Map接口

Map是集合框架中的另一个父接口,用于保存具有映射关系的数据,这样的数据称之为key-value键值对。key可以看成是value的

索引。

Set、List接口都属于单值的操作,而Map中的每个元素都使用key——>value的形式存储在集合中。对应set类似的罐子,Map算

是一个内部有分割空间并赋予标签的罐子

Map的特点

key和value也必须是引用类型的数据 

作为key的对象在Map集合中不允许重复

key可以为null  key和value之间存在单向一对一关系,通过指定的key总能找到唯一,确定的value

其实Map和Set可以放在一起记忆。它们表面上的功能比较类似

1)HashMap

 

HashMap的底层基于数组和链表来。它是通过计算散列码来决定存储的位置,所以有相当快的查询速度。

它就相当于以数组形式存储链表,然后用链表存储Key-value值。也就是散列表,它具有相当快的存储速度它之所以有相当快的查

询速度主要是因为它是通过计算散列码来决定存储的位置。

HashMap中主要是 通过key的hashCode来计算hash值的,只要hashCode相同计算出来的hash值就一样。如果存储的对象对多

了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。

 当向HashMap中添加元素时,我们先通过key的hash值经过一系列的计算算出所在数组中的位置,如果此位置上已经有元素了,

那么我们在通过equals方法与此位置上的单向链表内的元素一一比较, 如果有相同的key,就会替换原有的key-value,如果没有,

添加在 此单向链表中. 如果此位置上没有元素,就直接存储在此位置上对应单向链表的头节点上。
  
  现在的问题就是怎么解决作为key对象的hash值有可能与其他key的hash值冲突问题(此时应该尽量避免单向链表的产生)

   怎么解决:
      Object类的hashCode方法是:返回对象的散列值,这个值是根据对象的内存地址经过hash算法处理后的一个int值。(如果不

重写,这个算法不可控,相撞的几率就非常大)因此,我们需要重写,让相撞的几率更小。

如何重写hashCode方法,我截了张图。

说白了:就是让所有的成员变量都参与运算,设计一个复杂的公式, 尽可能的减少hash值的碰撞。  
    
2)HashTable

HashMap 和 Hashtable 是 Map 接口的两个典型实现类

区别:

Hashtable 是一个古老的 Map 实现类,不建议使用

Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。

Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以

 与 HashSet 集合不能保证元素的顺序的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序
 

3).    LinkedHashMap

    LinkedHashMap 是 HashMap 的子类

    LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致

4).    TreeMap

    TreeMap 存储 Key-Value对时,需要根据 Key 对 key-value 对进行排序。

    TreeMap 可以保证所有的 Key-Value 对处于有序状态。

    TreeMap 的 Key 的排序:

 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出

ClasssCastException

 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。

此时不需要 Map 的 Key 实现 Comparable 接口

5)装载因子及其HashMap优化:

a)capacity:容量,hash表里bucket(桶)的数量,也就是散列数组大小

b)initial capacity:初始容量,创建hash表时,初始bucket的数量,默认构建容量为16,也可以使用特定容量。

c)size:大小,当前散列表中存储数据的数量

d)load factor:加载因子,默认值0.75也就是75%,当向散列表增加数据时,如果size/capacity的值大于loadfactor。则发生扩容并

  且重新散列(rebash)

       性能优化:加载因子较小时,散列查找性能会提高, 但是也浪费了散列桶空间容量。0.75是性能和空间相对平衡结果。在创

建散列表时指定合理容量,减少rehash能提供性能ashMap优化。
 

4.比较

5.总结

List:add/remove/get/set。

    1,ArrayList:其实就是数组,容量一大,频繁增删就是噩梦,适合随机查找;

    2,LinkedList:增加了push/[pop|remove|pull],其实都是removeFirst;

    3,Vector:历史遗留产物,同步版的ArrayList,代码和ArrayList太像;

    4,Stack:继承自Vector。Java里其实没有纯粹的Stack,可以自己实现,用组合的方式,封装一下LinkedList即可;

    5,Queue:本来是单独的一类,不过在SUN的JDK里就是用LinkedList来提供这个功能的,主要方法是offer/pull/peek,因此归到这里呢。

  Set:add/remove。可以用迭代器或者转换成list。

    1,HashSet:内部采用HashMap实现的;

    2,LinkedHashSet:采用LinkedHashMap实现;

    3,TreeSet:TreeMap。

  Map:put/get/remove。

    1,HashMap/HashTable:散列表,和ArrayList一样采用数组实现,超过初始容量会对性能有损耗;

    2,LinkedHashMap:继承自HashMap,但通过重写嵌套类HashMap.Entry实现了链表结构,同样有容量的问题;

    3,Properties:是继承的HashTable。

    顺便说一下Arrays.asList,这个方法的实现依赖一个嵌套类,这个嵌套类也叫ArrayList!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值