《Java 编程思想》--第十七章:容器深入研究

  1. 每个java.util容器都有自己的Abstract类,他们提供了该容器的部分实现,所以只要去实现那些想要的容器所必须的方法,就可以创建新的容器
  2. Collection执行的所有操作
    1. boolean add(T)确保容器持有具有泛型类型T的参数,如果没有将此参数添加进容器,则返回false
    2. boolean addAll(Collection <? extends T>)添加参数中的所有元素,只要添加了任意元素就返回true
    3. void clear() 移除容器中的所有元素
    4. boolean contains(T) 如果容器中已经持有泛型类型T此参数,则返回true
    5. Boolean containsAll(Collection<?>)如果容器持有此参数中的所有元素,则返回true
    6. boolean isEmpty()  容器中没有元素时返回true
    7. Iterator<T> iterator()  返回一个Iterator<T> , 可以用来遍历容器中的元素
    8. Boolean remove(Object)  如果参数在容器中,则移除此元素的一个实例,如果做了一处操作,则返回true
    9. boolean removeAll(Collection<?>) 移除参数中的所有元素,只要有移除动作就返回true
    10. Boolean retainAll(Collection<?>) 只保存参数中的元素,只要Collection发生了改变就返回true
    11. int size() 返回容器中元素的数目
    12. Object[]  toArray() 返回一个数组,该数组包含容器中的所有元素
    13. <T> T[] toArray(T[] a)返回一个数组该数组包含容器中的所有元素,返回结果的运行时类型参数与参数数组a的类型相同,而不是单纯的Object
  3. 将方法定义为可选,那是因为这样做可以防止在设计中出现接口爆炸的情况
  4. java容器类库的一个重要目标:容器应该易学易用
  5. UnsupportedOperationException:
    1. 它必须是一个罕见的事件
    2. 如果一个操作时未获支持的,那么在实现接口的时候可以抛出这个异常
  6. 如果一个对象被用于任何种类的排序容器中,例如SortedSet(TreeSet是其唯一实现),那么它必须实现这个接口。实现其中的compareTo(),如果equals()对于某个特定比较产生true,那么compareTo()对于该比较应该返回0,如果equals()对于某个比较产生false,那么compareTo()对于该比较应该返回非0值
  7. LinkedHashSet按照元素插入的顺序保存元素,而TreeSet按照排序顺序维护元素
  8. SortedSet:
    1. Comparator comparator()返回当前set使用的Comparator,或者返回null,表示自然方式排序
    2. Object first()返回容器总的第一个元素
    3. Object last()返回容器中的最末一个元素
    4. SortedSet subSet(fromElement, toElement)生成此Set的自己,范围从fromElement(包含)到toElement(不包含)
    5. SortedSet headSet(toElement)生成此Set的子集,由小于toElement的元素组成
    6. SortedSet tailSet(fromElement)生成此Set的子集,由大于或等于fromElement的元素组成
  9. SortedSet的意思是“按对象的比较函数对元素排序”,而不是指“元素插入的次序”。插入顺序可以用LinkedHashSet来保存
  10. Queue在java se5中只有两个实现,LinkedList和PriorityQueue,他们的差异在排序行为
    1. PriorityQueue的排序也是通过Comparable而进行控制
  11. 双向队列:
    1. 就像是一个队列,但是可以在任何一段添加或移除元素,在LinkedList中包含支持双向队列的方法,但是在java标准类库中没有任何显式地用于双向队列的接口。因此可以使用组合来创建一个Deque类,并直接从LinkedList中暴露
  12. 映射表(也称为关联数组)的基本思想是它维护的是键值(对)关联,因此你可以使用键来查找值。标准的java类库中包含了Map的几种基本实现,包括
    1. HashMap:使用了hashCode()来进行散列,hashCode为java的Object根类的方法,插入和查询“键值对”的开销是固定的,可以通过构造器设置容量和负载因子,以调整容器的性能
      1. 默认的Object.equals()比较的是对象的地址
      2. HashMap使用equals()判断当前键是否与表中存在的键相同,正确的equals应满足以下5个条件
        1. 自反性:x.equals(x) = true
        2. 对称性:若x.equals(y)= true,则y.equals(x)=true
        3. 传递性:对任意x,y,z若x.equals(y)=true,且y.equals(z)=true,则x.equals(z)=true
        4. 一致性:对于任意x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回结果总是一致地
        5. 对任何不是null的x,x.equals(null)一定返回false
      3. 如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法
    2. TreeMap:基于红黑树的实现,查看“键”或“键值对”时,他们会被排序(次序由Comparable或Comparator)决定。TreeMap的特点在于,所得到的结果是经过排序的。TreeMap是唯一带有subMap()方法的Map,可以返回一个子树
      1. Comparator comparator():返回当前Map使用的Comparator,如果返回null,表示以自然方式排序
      2. T firstKey():返回Map中的第一个键
      3. T lastKey():返回Map中的最末一个键
      4. SortedMap subMap(fromKey,toKey):生成此Map的子集,范围由fromKey(包含)到toKey(不包含)的键确定
      5. SortedMap headMap(toKey):生成此Map的子集,由键小于toKey(不包含)的键值对组成
      6. SortedMap tailMap(fromKey):生成此Map的子集,由键大于或等于fromKey的所有键值对组成
    3. LinkedHashMap:类似于HahsMap,但是迭代遍历它取得“键值对”的顺序是其插入次序,或者是LRU次序,只比HashMap慢一点,而在迭代访问时反而更快,因为它使用链表维护内部次序
      1. 散列话所有的元素,但是在遍历键值对时,却又以元素的插入顺序返回键值对
      2. 可以在构造器中设定LinkedHashMap,使之采用基于访问的最近最少使用(LRU)算法,没有访问过的元素就会出现在队列的前面
    4. WeakHashMap:弱键(weak key)映射,允许释放映射所指向的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向“某个键”,则此“键”将被GC回收
    5. ConcurrentHashMap:一种线程安全的Map,他不涉及同步加锁
    6. IdentityHashMap:使用==代替equals()对“键”进行比较的散列映射,专门为解决特殊问题而设计的
  13. 如果不覆盖hashCode()和equals()将无法使用散列的数据结构有:
    1. HashSet
    2. HashMap
    3. LinkedHashSet
    4. LinkedHashMap
  14. 散列的价值在于速度:三烈士的查询得以快速进行。由于瓶颈位于键的查询速度。
  15. 散列冲突:
    1. 如果能够保证没有冲突(如果值的数量是固定的,那么就有可能),那可就有了一个完美的散列函数
    2. 冲突由外部链接处理:数组并不直接保存值,而是保存值得list,然后对list中的值使用equals()方法进行线性查询
    3. 为了使散列均匀分布,通常桶(槽)的数量为质数
  16. 设计hashCode()时最重要的因素就是:无论何时,对同一个对象,调用hashCode()都应该生成同样的值
  17. String的hashCode()生成的同样的结果
  18. hashCode()给出的基本指导:
    1. 给int变量result赋予某个非零值常量
    2. 对每个对象内有个意义的域f,计算出一个int散列码c:
      1. booean:c=(f?0:1)
      2. byte,char,short或int:c=(int)f
      3. long:c=(int)(f^f>>>32)
      4. float:c=Float.floatToIntBits(f)
      5. double:long l = Double.doubleToLongBits(f);   c=(int)(l ^ (l>>>32));
      6. Object:c=f.hashCode()
      7. 数组:对每个元素应用上述规则
    3. 合并计算得到的散列码:
      1. result = 37 * result + c
    4. 返回result
    5. 检查hashCode()最后生成的结果,确保相同的对象有相同的散列码
  19. Set可被实现为:
    1. TreeSet:HashSet最常用,查询速度最快。它唯一原因是它可以维持元素的排序状态。TreeSet迭代通常比用HashSet要快
    2. HashSet:基于TreeMap。生成一个总是处于排序状态的Set。性能基本上总是比TreeSet好,特别是在添加和查询元素时,而这两个操作也是最重要的操作。
    3. LinkedHashSet:保持元素插入的次序。对于插入操作LinkedHashSet比HashSet的代价还高,这是由维护链表所带来额外开销造成的
  20. Map可被实现为:
    1. IdentityHashMap:所有的Map实现的插入操作都会随着Map尺寸的变大而明显变慢。查找的代价通常比插入要小得多
    2. HashTable的性能大体上与HashMap相当,HashMap是用来替代HashTable的
    3. TreeMap:通常比HashMap慢,与TreeSet一样,TreeMap是一种创建有序队列的方式
    4. LinkedHashMap:在插入时比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表,正是由于这个列表,使得其迭代速度更快
  21. HashMap的性能因子:
    1. 容量:表中的桶位数
    2. 初始容量:表在创建时所拥有的桶位数。HashMap和HashSet都具有允许你指定初始容量的构造器
    3. 尺寸:表中当前存储的项数
    4. 负载因子:尺寸/容量
  22. HashMap使用的默认负载因子0.75,这个因子在时间和空间代价之间达到了平衡,更高的负载因子可以降低表所需的空间,但是会增加查找代价
  23. Java容器类类库采用快速报错机制。快速报错机制的工作原理:只需创建一个迭代器,然后向迭代器所指向的Collection添加点什么
  24. java.lang.ref类库包含了一组类,有三个继承自抽象类Reference的类:SoftReference,WeakReference和PhantomReference。当垃圾回收器正在考察的对象只能通过某个Reference对象才“可获得”时,上述这些不同的派生类为垃圾回收器提供了不同级别的间接性只是。
  25. 对象是可获得的,是指此对象可在程序中的某处找草,这意味着你在栈中有一个普通的引用,而它正指向此对象。如果一个对象是“可获得的”,垃圾回收器就不能释放它,因为它仍然为你的程序所用。如果一个对象不是“可获得的”,那么你的程序无法使用到它,所有将其回收是安全的
  26. SoftReference、WeakReference和PhantomReference由强到弱排列,对应不同级别的“可获得性”
    1. SoftReference:用以实现内存敏感的高速缓存
    2. WeakReference:为实现“规范映射”而设计的,它不妨碍垃圾回收器回收映射的“键”(或“值”)。规范映射中对象的实例可以在程序的多处被同时使用,以节省存储空间
    3. PhantomReference:用一调度会收钱的清理工作,它比Java终止机制更灵活
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值