Java编程思想之容器深入研究

1.     每个Java.util容器都有其自己的Abstract类,它们提供了改容器类的部分实现,因此只需实现那些产生想要容器所必需的方法。

2.     设计模式:享元。享元模式使得对象的一部分可以被具体化,因此与对象中的所有事物都包含在对象内部不同,可以在更加高效的外部表中查找对象的一部分或整体。比如对象内部只存储外部表的索引。

3.     可选操作:实现类并不需要为这些方法提供功能定义。它声明调用某些方法将不会执行有意义的行为,相反,它们会抛出未获支持操作异常。未获支持操作是一种特例,可以延迟到需要时再实现。如果操作是未获支持的,那么在使用接口时候会导致UnsupportedOperationException异常。未获支持的操作只有运行时才能探测到,表示动态类型检查。比如:基于固定大小数组结构的容器,仅支持那些不会改变数组大小的操作。

4.     加入Set的元素必须定义equal方法来保证对象的唯一性,但不保证维护元素的次序。加入HashSet的元素必须定义hashCode(),加入treeSet的元素必须实现Comparable接口,LinkedHashSet具有HashSet的查询速度,且内部使用链表维护元素的插入顺序,也必须定义hashCode()方法。对于没有重新定义HashCode()的类型对象,如果将它们放置到任何散列实现中都会产生重复值,就违反了Set的基本契约。

5.     SortedSet可以按照对象的比较函数对元素排序,而不是指元素插入的次序。

6.     Queue的两个实现功能类:LinkedList和PriorityQueue。在LinkedList中包含支持双向队列的方法。

7.     TreeMap基于红黑树的实现。Map中键必须唯一,而值可以重复。SortedMap确保键处于排序状态。可以在构造器中设定LinkHashMap,使之采用基于访问的最近最少使用算法(LRU),于是没有被访问过的元素就会出现在队列的最前面。

8.     默认的hashCode()使用对象的地址计算生成散列码,默认的equals()比较对象的地址。

9.     hashCode()并不总需要总是返回唯一的标识码,但是equals()必须严格判断两个对象是否相同。当在HashSet中使用自定义的类时,必须注意这个问题。

10.  使用散列的目的在于:想要使用一个对象来查找另一个对象,提高查询速度。散列将键存在数组的某处,通过键对象的hashCode()的返回值通过散列函数映射到某个数字,将其作为数组的下标,这个数字就是散列码。

11.  不同的键可以产生相同的下标,即冲突。因此,数组多大不重要,任何键总能在数组中找到它的位置。

12.  查找一个值的过程首先是计算散列码,然后使用散列码查询数组。通常,冲突由外部链接处理:数组并不直接保持值,而是保存值的List。每个新元素都直接添加到list末尾。然后对list中的值用equals()方法进行线性查询。不是查询整个List,而是快速跳到数组的某个位置,只对很少元素进行比较,因此HashMap会如此快。

13.  散列表的槽位通常称为桶,为使散列分布均匀,桶的数量通常使用质数或者2的整数次方,相应的散列函数为除法求余数和2的整数次方。

14.  无法控制数组的下标值的产生,这个值依赖于具体HashMap对象的容量,而容量与容器的充满程度和负载因子有关。

15.  无论何时,对同个对象调用hashCode()都应生成同样的值。当心hashCode()方法依赖于对象中易变的数据,因为此数据变化时,hashCode()会生成不同的散列码,相当于产生不同的键。也不应该使hashCode()依赖于具有唯一性的对象信息,因为这样做无法生成新的键,使之与put()中原始的键值对中的键相同。应该使用对象内的有意义的识别信息。

16.  String类如果有多个相同字符串的对象,那么这些对象都映射到同一块内存区域,即hashCode()基于String内容。

17.  想要hashCode()使用,它必须有意义,基于对象的内容生成散列码,散列码不必要独一无二,但是通过hashCode()和equals(),必须能够完全确定对象的身份。好的hashCode()应该可以产生分布均匀的散列码。Effective Java提供了hashCode()的基本指导。

18.  选择接口的不同实现基于查看容器实现之间的差异,使用性能测试框架。

19.  最佳做法是将ArrayList作为默认首选,只有需要使用额外功能,或者程序性能因为经常从表中间进行插入和删除而变差的时候,才选择LinkedList。如果使用的是固定元素,那么可以选择数组或背后有数组支撑的List。

20.  容量:表中的桶数。

21.  初始容量:在创建时所拥有的桶位数,HashMap和HashSet具有指定初始容量的构造器。

22.  尺寸:表中当前存储的项数。

23.  负载因子:尺寸/容量。

24.  负载轻的表产生冲突的可能性少,因此对于插入和查找都是最理想的。HashMap和HashSet具有指定负载因子的构造器,表示负载情况达到该负载因子水平时,容器将自动增加其容量,实现方式是使容器大致加倍,并重新将现有对象分布到新的桶位集中。HashMap默认的负载因子是0.75。如果知道将在HashMap存储项数,那么创建一个具有恰当大小的初始容量将可以避免自动再散列的开销。

25.  可以设定Collection和Map为不可修改,作为private成员,只有创建者可以修改容器的内容,而别人只能读取。

26.  Collection和Map的同步控制。

27.  Java容易采用快速报错机制,能够防止多个进程同时修改同一个容器的内容。它会探查容器上的任何除了你的进程所进行的操作以外的所有变化,一旦发现了其他进程修改了容器,就会立刻抛出ConcurrentModificationException异常。

28.  持有引用:三个继承子抽象类Reference的类,SoftReference,WeakReference和PhantomReference。当垃圾回收器正在考察的对象只能通过某个Reference对象才能可获得时,这些不同的派生类为垃圾回收器提供了不同级别的间接性指示。

29.  如果一个对象是“可获得的”,垃圾回收器就不能释放它,因为它仍然为程序所用。如果一个对象不是“可获得的”,那么程序将无法使用它,所以将其回收是安全的。

30.  使用Reference对象时,你可以继续使用该对象,而在内存消耗殆尽时又允许释放该对象。

31.  以Reference对象作为普通引用的代理,另外,一定不能有普通引用指向哪个对象,这样就能达到上述目的。

32.  SoftReference,WeakReference和PhantomReference有强到弱,对应不同级别的可获得性。SoftReference只有在内存不够时才会回收,WeakReference不妨碍链接回收器回收映射的键,PhantomReference用以调度会收钱的清理工作,比终止机制灵活。

33.  SoftReference,WeakReference可以选择是否将它们放入ReferenceQueue,PhantomReference只能依赖于ReferenceQueue。

34.  WeakHashMap允许垃圾回收器自动清理键和值,映射会自动使用WeakReference包装键和值。允许清理元素的出发条件是,不在需要此键了。

35.  BitSet用来高效率存储大量的“开关“信息,最小容量是long:64位。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值