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