Java容器框架提供了多种不一样特性的容器方便咱们管理任意数量的对象。java
11.1泛型和类型安全的容器编程
JavaSE5以前的容器容许咱们向其中放入不一样类型的对象,可是取出的时候须要进行类型强制转换,很容易出现问题。有了泛型以后须要咱们只能向集合里添加指定类型及其子类,取出时也不须要类型转换,这个功能是编译器完成的。数组
11.2基本概念安全
Java中容器分为2个概念:并发
1)Collection:一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入顺序保存元素,Set不能有重复元素。Queue按照排队规则肯定对象产生的顺序(一般与插入顺序相同)。框架
2)Map:映射表容许咱们使用另外一个对象来查找某个对象,它也被称为关联数组。性能
理想状况下在建立对象时向上转型成接口,方便切换实现,除非须要用到特有方法。测试
11.3添加一组元素优化
java.util包里Arrays和Collections类有不少实用方法,能够在一个Collection里添加一组元素。spa
Arrays.asList()接受一个数组或者可变长参数,转换成一个固定长度(不能add)的list。
Collections.addAll()接受一个Collection对象和一个可变长参数,向Collection里添加一组元素。
Collection.addAll()只能接收一个Collection对象,没有上面灵活。
首选:Collections.addAll()
注意Arrays.asList()对产生的List类型作了最理想的假设:即最近公共父类,这可能会产生问题。
好比:父类Person,一级子类Man,二级子类WhiteMan、BlackMan
List<Person> list = Arrays.asList(new WhiteMan(),new BlackMan());
这时会编译出错,由于编译器找到理想的类型是List<Man>而不是List<Person>,咱们须要手动指定asList类型:
List<Person> list = Arrays.<Person>asList(new WhiteMan(),new BlackMan());
使用Collections.addAll()不须要指定类型,由于第一个参数里已经有类型了。
11.4容器的打印
容器类不须要作特殊处理便可直接打印,而且能够生成格式很好的输出。
11.5List
List能够把元素维护在特定的序列里,在Collection基础上添加了不少操做index的方法,如获取,设置,插入,删除。contains()/remove()/indexOf()等行为是根据equals()结果来的。
ArrayList提供高效访问,低效插入删除。LinkedList相反,通常状况使用ArrayList除非进行大量插入删除使用ArrayList影响性能了才改用LinkedList。
subList()能够返回大List里的一个子List,至关于对象引用copy了一份,因此list.containsAll(subList)是true,对subList元素的操做也会影响原来的list。
retainAll()交集操做,保留两个list里的共同元素,基于equals()。
其余方法...
11.6迭代器
任何容器都必须有某种方式能够插入元素并把它取回。对于List能够用get取出,若是从更高层次思考,会发现要使用容器,必须对容器的确切类型编程。若是咱们可使得对List使用的代码也能够对Set使用,就会很是方便。迭代器Iterator就是用于这种目的,使得咱们不须要关心序列的底层结构就可使用next()、hasNext()、remove()来遍历或删除序列中的元素。若是只是遍历不须要修改List,使用foreach更加方便。
remove()用了删除最后一次next()获得的元素,因此必须先使用next()取得元素,而后才能remove()
11.6.1ListIterator
是一个更增强大的Iterator子类型,但只能用于List类型的访问。容许进行双向(先后)访问,可使用set替换被访问的最后一个元素,能够用listIterator(n)重载方法建立一个一开始就指向索引为n的ListIterator.
11.7LinkedList
LinkedList相比ArrayList除了某些操做性能不一样以外,还添加了可使其用做栈,队列或双端队列的方法。不少方法名称不一样可是做用差很少,主要用于在不一样上下文环境下使用。如element() getFirst(),remove(),removeFirst(),peek(),pop()等。
11.8Stack
后进先出,就像弹夹同样的储存装置。LinkedList有实现栈功能的全部方法,能够直接做为栈使用,可是有时候用一个真正的栈更能够把问题解决清楚优雅。
Java中提供了java.util.Stack类用于模拟一个Stack,可是设计的并不恰当:
1)Stack从Vector继承而来,多了不少没必要要的方法,并且有的方法会破坏Stack的规则:如add(index,obj)
2)Vector是数组实现的,在push()pop()时候效率很低,应该使用链式结构
咱们能够本身写一个:
public class Stack<T>{
private LinkedList<T> list = new LinkedList<>();
public void push(T t){list.addFirst(t);}
public T peek(){return list.getFirst();}
public T pop(){return list.removeFirst();}
public boolean empty(){return list.isEmpty();}
public String toString(){return list.toString();}
}
11.9Set
Set不保存重复的元素,最经常使用的功能就是测试是否包含对象,所以查找就成为了Set中最重要的操做,HashSet实现专门对快速查找进行了优化。
Set与Collection接口彻底一致,只是行为不一样(多态的特性)。Set是根据对象的值来决定归属性的。
11.10Map
把对象映射到其它对象的能力是解决不少问题的杀手锏。
遍历时能够返回键的set或者键值对的set
11.11Queue
队列是典型的先进先出FIFO容器,取出顺序与放入顺序一致。是一种可靠的把对象从程序的某个区域传输到另外一个区域的途径。在并发编程中特别重要。
LinkedList提供了方法能够支持队列行为,而且也实现了Queue接口,因此它能够用做Queue的一种实现。
Queue<Integer> q = new LinkedList<>();
offer():插入队尾或返回false
peek()/element()返回队头,队列为空时peek返回null,element抛出NoSuchElementException
poll()/remove()返回队头并移除,队列为空时pool返回null,remove抛出NoSuchElementException
11.11.1PriorityQueue
队列规则:给定一组队列元素,肯定下一个弹出元素的规则。先进先出是典型的一种队列规则。
优先级队列声明下一个弹出元素是优先级最高的元素。PriorityQueue在JavaSE5开始出现,默认元素顺序是按照天然顺序弹出,能够设置一个Comparator来控制这种优先级。
11.12Collection和Iterator
实现Collection接口就必须提供建立Iterator的方法,保证了通用能力。
11.13ForEach与迭代器
任何实现了Iterable接口的类,均可以在foreach中使用。数组和Collection类均可以使用。但Map不行。
11.13.1适配器方法惯用法
使用不一样的方法产生不一样的Iterator,用于不一样的迭代方式。
11.14总结
Java提供了大量持有对象的方式:
1.数组,保存单一类型对象,能够是多维的,能够保存基本类型,可是容量不可变。
2.Collection保存单一元素,Map保存键值对。有了泛型不须要进行类型转换,不可持有基本类型可是会自动包装来处理,容量可变。
3.List也创建了数字和对象的关联,因此数组和List都是排序好的容器。List能自动扩容
4.大量随机访问用ArrayList,常常中间插入删除用LinkedList。
5.队列以及堆栈行为用LinkedList完成。
6.Map是一种将对象与对象相关联的设计。HashMap用于快速访问,TreeMap保持键始终处于排序状态,没有HashMap快。LinkedHashMap保持元素插入顺序,可是也经过散列提供了快速访问的能力。
7.Set不接受重复元素。HashSet提供最快查询速度,TreeSet保持元素处于排序状态,LinkedHashSet以插入顺序保存元素,查询也快。
8.不该该使用过期的Vector(同步效率慢,扩容时候翻倍ArrayList扩一半),HashTable(同步效率慢),Stack
集合框架图: