第十七章:容器深入研究

填充容器

  1. new ArrayList(Collections.nCopies(size, item))和Collections.fill(list, item)
  2. 一种Generator解决方案
    所有Collection子类型都有一个接收另一个Collection对象的构造器,用所接收的Collection对象中的元素来填充新的容器。或者使用Collection.addAll(Generator)。
  3. //适配器模式的实例
    public class CollectionData extends ArrayList{
      public CollectionData(Generator gen, int quantity){
        for(int i = 0; i< quantity; i++){
          add(gen.next());
        }
      }
      
      //a generic convenience method;
      public static  CollectionData list(Generator gen, int quantity){
        return new CollectionData(gen, quantity);
      }
    }
    
    1. Map生成器:
      Map可以使用相同方式,但需要一个Pair类。然后使用Generator>的对象填充map。
    public class Pair{
      public final K key;
      public final V value;
      public Pair(K k, V v){
        key = k;
        value = v;
      }
    }
    
    1. 使用Abstract类
      **享元模式:采用一个共享来避免大量拥有相同内容对象的开销。这种开销中最常见、直观的就是内存的损耗。享元模式以共享的方式高效的支持大量的细粒度对象。java的String对象的创建就是享元模式。
      为了创建只读的Map,可以继承AbstractMap并实现entrySet(),为了创建只读的Set,可以继承AbstractSet并实现iterator()和size()。享元在于子类只存储索引,通过索引读取内容。

    可选操作

    执行各种不同的添加和移除的方法在Collection都是可选操作,如果调用没有实现的方法,会抛出UnsupportedOperationException。这是为了防止接口爆炸。
    最常见的未获支持的操作,都来源于背后由固定尺寸的数据结构支持的容器,比如Arrays.asList()将数组转换为List时,就会得到这样的容器,或者Collections.unmodifiableList()返回的容器。所以,应该把这种结果作为构造器参数传递给任何Collection,这样就可以产生尺寸可调整的容器。

    Set和存储顺序

    Set(interface) 存入Set的每个元素都必须是唯一的,加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口,Set不保证维护元素的次序。
    HashSet(默认) 为快速查找而设计的Set。存入HashSet的元素必须定义hashCode()
    TreeSet 保存次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。元素必须实现Comparable接口
    LinkedHashSet 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的顺序)。bianlishi,以插入顺序显示。元素也必须定义hashCode()方法。

    对于良好的编程风格来说,你应该在覆盖equals()方法时,总是同时覆盖hashCode()方法。
    SortedSet接口:比如TreeSet就是其中一个实现。

    队列

    Queue接口两个实现是LinkedList和PriorityQueue,差异在于排序行为而不是性能。
    优先级队列:优先级队列的元素需要实现Comparable。
    双向队列:可以在任何一段添加或移除元素。LinkedList包含支持双向队列的方法,但是java标准库中没有这样的接口。

    Map

    1. 性能:
      HashMap使用散列码——“相对唯一”来代表对象的int值。如果不能满足你的要求,可以创建自己的Map来进一步提高查询速度。
    HashMap* 基于散列表实现,插入和查询“键值对”的开销是固定的。可以通过构造器设置容量和负载因子,以调整容器的性能。
    LinkedHashMap 取得键值对是插入顺序,或是最近很少使用(LRU)顺序。只比HashMap慢一点,迭代访问时更快,因为使用链表维护内部次序。以插入顺序返回键值对迭代遍历。
    TreeMap 基于红黑树的实现。查看键或键值对时,它们会被排序(次序有Comparable或Comparator决定)。得到结果是经过排序的。唯一带有subMap()的Map,可以返回一个子树。
    WeakHashMap 弱键映射,允许释放映射所指向的对象。如果映射之外没有引用指向某个键,该键可以被垃圾回收。
    ConcurrentHashMap 线程安全的Map,不设计同步加锁。
    IndentityHashMap 使用==代替equals()对键进行比较的散列映射。专为特殊问题设计

    *任何键都必须具有equals()方法。
    *SortedMap接口:TreeMap是其唯一实现。

    散列与散列码

    HashMap使用equals()判断当前的建是否与表中存在的键相同。
    HashMap的性能因子:

    1. 容量:表中的桶位数
    2. 初始容量:表在创建时所拥有的桶位数。HashMap和HashSet都具有允许你指定初始容量的构造器。
    3. 尺寸:表中当前存储的项数
    4. 负载因子:尺寸/容量。空表的负载因子为0,班满表的负载因子是0.5,负载轻的表产生冲突的可能性小,因此对于插入和查找都是最理想的,但会减慢使用迭代器遍历的过程。HashMap和HashSet都具有允许你指定负载因子的构造器,表示当负载情况达到该负载因子的水平时,容器将自动增加其容量(容量),实现方式是使容量加大一倍,并重新将现有对象分布到新的桶位几种(再散列)。

    Collections有用的api

    快速报错

    java容器有一种保护机制,当你调用iterator()获取迭代器后,再想迭代器所指向的Collection添加点什么,就会抛出ConcurrentModificationException异常。

    持有引用

    如果想继续持有对某个对象的引用,希望以后还能够访问到该对象,但是也希望能够允许垃圾回收器释放它,这是就应该使用Reference对象。一般是以Reference对象作为你和普通引用之间的媒介(代理),另外一定不能有普通的引用指向那个对象。
    Reference抽象类的导出类:SoftReference(内存敏感的高速缓存),WeekReference(目的是“规范映射”,不妨碍垃圾回收器回收映射的键或值,“规范映射”中对象的实例可以在程序的多处被同时使用,以节省存储空间),PhantomReference(调度回收前的清理工作,比Java终止机制灵活),由强到弱排列,对应不同级别的可获得性。PhantomReference只能放入ReferenceQueue,其余两者可选。
    补充资料1
    补充资料2

    Java 1.0/1.1 的容器

    1. Vector:自我扩展的序列=>ArrayList
    2. Enumeration:接口,hasMoreElements()、nextElement()。
    3. HashTable => HashMap
    4. Stack:继承Vector
    5. BitSet:高效率的存储大量“开/关”信息,最小容量为long:64位,自动扩容(都是64的倍数),若存储的内容比较小,就浪费了一些空间。补充

    你可能感兴趣的:(第十七章:容器深入研究)