java集合框架

接口和实现分离

使用接口类型存放集合的引用

优势:

  1. 构建集合后就不需要知道使用哪种实现
  2. 更改实现时只需要更改调用构造器的地方。

如果需要实现自己的集合类,可以扩展一组以Abstract开头的类,扩展这些类比实现接口中所有方法轻松的多。

接口

  1. Collection

两个基本方法

public interface Collection<E>
{
    boolean add(E element);
    Iterator<E> iterator();
    ...
}
  • 迭代器 Iterator
    public interface Iterator<E>{
      E next();
      boolean hasNext();
      void remove();
      default void forEachRemaining(Conseumer<? super E> action);
    }
  1. List

有序集合,访问方式:迭代器和整数索引

数组的有序集合可以快速随机访问,链表随机访问很慢,最好使用迭代器遍历

  1. set

集:add方法不允许增加重复的元素

集的equals方法需要保证两个集包含相同的元素就认为是相等的,不要求顺序.

hashcode()方法也要保证拥有相同元素的两个集得到相同的散列码.

  1. SortedSet

会提供用于排序的比较器对象,定义了可以得到集合子集视图的方法

  1. SortedMap

同上.

  1. NavigableSet

包含一些用于搜索和遍历有序集和映射的方法.

  1. NavigableMap

同上.

集合框架关系图

具体集合

除了以Map结尾的类都实现了Collection接口,Map结尾的类实现了Map接口

集合类型描述
arrayList动态增长和缩减的索引序列
Linkedlist在任意位置高效插入和删除的有序序列
ArrayDeque循环数组实现的双端队列
HashSet没有重复元素的无序集合
TreeSet有序集
EnumSet包含枚举类型的集
LinkedHashSet记住元素插入顺序的集
PriorityQueue允许高效删除最小元素的集合
HashMap存储键值对的数据结构
TreeMap键值有序排列的映射表
EnumMap键值属于枚举类型的映射表
Lindedhashmap记住键值项8添加次序的映射表
weakHashMap其值无用武之地后被回收的映射表
identityHashMap用==而不是equals比较键值的映射表

linkedList

linkedList.add()将元素添加到链表尾部.

contains()方法检测元素是否存在于链表中.

get(n)返回第n个元素.效率不高不建议使用.

索引大于n/2时从尾端开始搜索

ListIterator接口

依赖位置的add方法由迭代器负责.iterator的子接口ListIterator包含add方法和prevous和hasprevious方法用于反向遍历链表.

add方法依赖于迭代器的位置.remove方法依赖于迭代器的状态,不能多次调用remove方法.

nextIndex和previousIndex返回下一次调用next返回元素的整数索引,pre返回下一次previous返回元素的整数索引,效率很高因为迭代器保持着当前位置的计数值

arraylist

数组列表,实现了动态再分配的对象动态数组,实现了list接口

与vector对比,vector所有方法都是同步的,可以多线程安全访问一个vector对象,但是如果只有一个线程访问,代码需要在同步操作上耗费大量时间.而arraylist不是同步的

建议不需要同步是用arraylist,需要同步时使用vector

hashtable

散列表为每一个对象计算一个整数,称为散列码(hashcode).

java中散列表用链表数组实现,每个列表称为桶,要查找表中对象的位置,先计算散列码然后与桶数取余就是保存这个元素的桶的索引

桶被占满的情况称为散列冲突,需要新对象与桶中所有对象进行比较查看是否已经存在.

java se8中桶满时会从链表变为平衡二叉树,选择的散列函数不当会产生很多冲突,或者有恶意代码试图在散列表中填充多个相同散列码的值,这样可以提高性能.

有人认为最好将桶数设置为素数,防止键的集聚.标准库使用的桶数是2的幂,默认值为16,为表大小提供的值会自动转换为下一个2的幂.

装填因子,默认0.75.表中超过装填因子的位置已经填入元素则会以双倍的桶数进行再散列.

treeSet

树集是一个有序集合,任意顺序插入后,遍历时都是自动按照排序后的顺序呈现.

排序使用树结构完成,当前是红黑树.

将元素添加到树中会比添加到散列表慢,但是会比检查重复的数组和链表快很多.树中包含n个元素,插入元素大概要比较log 2 n次

java se 6 开始 treeSet实现了NavigabnleSet接口 增加了定位元素以及反向遍历的方法

arrayDeque和linkedList

  • 实现了双端队列Deque接口

priorityqueue优先级队列

  • 任意顺序插入,按照排序的顺序进行检索.
  • 调用remove总会获得当前优先级队列最小元素
  • 并没有排序
  • 使用堆实现,是自我调整的二叉树,使用add和remove后会自动让最小的元素移动到根
  • 典型用例:任务调度

映射

  • 包括hashMap和treeMap.treeMap包含插入顺序,hashmap无,hashmap稍快.
  • get方法没有与给定键对应信息是get返回null,
  • getOrDefault为键不存在时提供默认值
  • 键唯一,两次使用put会覆盖第一个值,put返回值为该键上一个值
  • 迭代映射使用foreach最方便,提供一个lambda表达式,映射中每一项会依次调用
    scores.forEach((k,v)->System.out.println("key="+k+"value="+v));

    更新映射项

    特殊情况:第一次出现时get返回null

解决方法:

  • counts.put(word,counts.getOrDefault(word,0)+1);
  • counts.putIfAbsent(word,0);counts.put(word,counts.get(word)+1);
  • counts.merge(word,1,Integer::sum);

映射视图

集合框架不认为映射是一种集合,但是可以获得键,值,键值对的集合.

  • set keySet()
  • collection values()
  • set> entrySet()

set接口扩展了collection接口所以可以像使用集合一样使用keyset

  • 键集视图调用remove会从映射中删除键值对
  • 不能向视图添加元素,调用add会抛出UnsupportedOperationException错误
弱散列映射

weakhashMap:由于映射一直活动导致垃圾回收器无法回收已经没有引用的值,所以需要程序自身对其进行回收,所以设计了weakHashMap.

  • 使用弱引用保存散列键,垃圾回收器发现某个对象只被弱引用引用则会回收它并将弱引用加入队列中.weakHashMap周期性检查队列,一旦弱引用加入队列意味着这个键不再被他人使用并且已被回收,然后weakHashMap删除这个条目.
链接散列集和映射

LinkedHashSet和LinkedHashmap记住插入元素项的顺序.

  • 链接散列映射使用访问顺序而非插入顺序进行迭代
  • 调用get或put将是条目从当前位置移动到链表尾部
  • 只影响条目在链表中的位置,散列表中的桶不受影响
  • 可以实现高速缓存的最近最少使用原则
枚举集与映射

EnumSet是枚举类型元素集的高效实现

  • 由于枚举类型只有有限个实例,所以内部用位序列实现
  • 对应的值在集中,对应位置1
  • 没有公共构造器,使用静态工厂方法构造
  • 使用set接口常用方法修改

EnumMap是键类型为枚举类型的映射,直接且高效的使用值数组实现,使用时,需在构造器中指定键类型

标识散列映射

IdentityHashMap

  • 使用System.identityHashCode计算散列码
  • 对象比较时使用==,非equals
  • 不同的键对象内容相同也视为不同对象
  • 实现对象遍历算法(如对象串行化)有用
视图与包装器
  • 视图并非创建新集,而是返回一个实现集合接口的类对象,方法操作的是原映射.视图技术在集框架有很多应用.视图包装了接口.

    • 轻量级集合包装器

      使用aslist(new card[100])等方法对数组等进行包装,可以使用get,set等方法,但是改变数组大小的方法都不可使用

    • 子范围
    • 不可修改视图
    • 同步视图
    • 受查视图

      受限于虚拟机的雨凝是检查,对于A>,无法阻止插入Pair

算法

泛型集合接口的很大一个优点就是,算法只需要实现一次.

public static <T extens Comparable> T Max (Collection<T> c){
    ...
}

就可任意使用一个方法计算链表,数组列表或数组中的最大元素了.

排序与混排

java中的排序将列表所有元素转入数组,然后对数组排序再将排序后的序列复制回列表

集合框架使用的排序算法为归并排序,慢于快排但是稳定,不需要交换相同值对象.

二分查找

  • collections.binarySearch方法实现了二分查找
  • 查找不到时返回负值i,将该值插入位置为-i-1可将该值插入并保持有序
  • 提供链表的话,它将自动变为线性查找

简单算法

collections类提供了复制列表到另一个,常量值填充容器,逆置列表的元素排序,获取最大等简单的算法.调用这些方法有益于代码可读性.

批操作

  • 批删除可以通过视图获得子集并调用clear方法
  • 求交集可使用retainAll(otherSet)方法
  • removeAll(otherSet)方法

集合和数组转换

数组转为集合

string [] values=...;
HashSet<String> staff=new HashSet<>(Arrays.asList(values));

从集合得到数组

object[] values=staff.toArray();

这样获得是对象数组

想获得字符串数组需要

string[] values = staff.toArray(new String[0]);

编写自己的算法(以集合为参数)

最好使用接口而不是具体的实现

遗留集合

  • hashTable:

    与vector相同,所有方法同步.对同步性无要求应使用hashMap

  • 枚举
  • 属性映射
  • 位集BitSet




原文地址:https://www.cnblogs.com/renluxiang/p/cf407b85b5c9dc5f0f30fc0a1a9db1f6.html