先来看几道题目:java
public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("Java"); set.add("JEE"); set.add("Spring"); set.add("Hibernate"); set = Collections.unmodifiableSet(set); set.add("Ajax"); // not allowed. }
能够看到,建立不可变集合主要是调用了Collections的unmodifiableSet()方法,而Collections类经过装饰模式实现了对通常集合的封装。面试
public static void main(String args[]) { List<String> list=new ArrayList(); list.add("A"); list.add("B"); list.add("C"); list.add("A"); // List中容许元素重复 for(int i=0;i<list.size();i++) System.out.print(" "+list.get(i));// A B C A // 去除重复的元素且保持原有元素的顺序 List list2=new testD().function(list); for(int i=0;i<list2.size();i++) System.out.print(" "+list2.get(i));// A B C } public <e> List<e> function (List<e> list) { return new ArrayList<e>(new LinkedHashSet<e>(list)); }
上面的代码代码经过把原有列表传入一个LinkedHashSet来去除重复的元素。在这个状况里,LinkedHashSet能够保持元素原来的顺序。若是这个顺序是不须要的话,那么上面的LinkedHashSet能够用HashSet来替换。数组
其实如上的两道题目并不难,只是没有对集合了解的更深。下面就来大概的看一下集合吧。集合的继承类以下所示。框架
如上的集合能够概括为三大类,即List、Set和Map。同时还有一些辅助的工具类,像Collections、Arrays等方便了集合的操做,各个集合的比较状况以下图。函数
其实对于集合的操做,无外乎就是工具
从Java集合框架图能够看出,全部的类都直接或间接继承了Iterable接口,源代码以下:this
package java.lang; import java.util.Iterator; /** * Implementing this interface allows an object to be the target of * the "foreach" statement. */ public interface Iterable<T> { Iterator<T> iterator(); // 返回一个在一组 T 类型的元素上进行迭代的迭代器 }
Iterable接口在java.lang包下,其中定义了一个获取Iterator的实例方法。spa
Iterator类的源代码以下:.net
public interface Iterator<E> { boolean hasNext(); // 是否含有下一个元素 E next(); // 获取集合的下一个元素 void remove(); // 从集合中移除当前元素 }
Iterator模式是用于遍历集合类的标准访问方法。它能够把访问逻辑从不一样类型的集合类中抽象出来,从而避免向客户端暴露出集合的内部结构。例如,若是没有使用Iterator,遍历一个数组的方法是使用索引: 设计
for(int i=0; i<集合的大小;i++){ // 省略操做代码 }
当访问一个链表(LinkedList)时又必须使用while循环:
while((e=e.next())!=null) { // 省略操做代码 }
以上两种方法遍历办法都必须事先知道集合的内部存储结构,访问代码和集合自己是紧耦合,没法将访问逻辑从集合类中分离出来,每一种集合对应一种遍历方法,客户端代码没法复用。 并且若是之后须要把ArrayList更换为LinkedList,则原来的客户端代码必需要进行重写。 为解决以上问题,Iterator模式老是用同一种逻辑来遍历集合:
for(Iterator it = c.iterater();it.hasNext(); ) { // ... }
设计的巧妙之处在于客户端自身不维护遍历集合的"指针",全部的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类经过工厂方法生成,所以,它知道如何遍历整个集合。值得提醒的是,这个工厂方法就是咱们前面提到的iterator()方法,由于全部的类都继承了Iterable接口,因此他的实现类必需要实现iterator()方法。
之后若是要访问集合时,就能够经过控制Iterator,向它发送"向前","向后","取当前元素"的命令,来间接遍历整个集合。
举例以下:
public class testSet { public static void main(String args[]) { // HashSet<String> ct = new HashSet<>(); // Set<String> ct=new HashSet<>(); // List<String> ct=new ArrayList<>(); List<String> ct=new LinkedList<>(); ct.add("abc"); ct.add("def"); for(Iterator<String> myitr = ct.iterator();myitr.hasNext();){ System.out.println(myitr.next()); } Iterator<String> iter = ct.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); } for (String str : ct) { System.out.println(str); } } }
使用了3种方法进行集合的遍历,输出的结果都是一致的,以下:
abc
def
abc
def
abc
def
每一种集合类返回的Iterator具体类型可能不一样,Array可能返回ArrayIterator,Set可能返回 SetIterator,Tree可能返回TreeIterator,可是它们都实现了Iterator接口,所以,客户端不关心究竟是哪一种 Iterator,它只须要得到这个Iterator接口便可,这就是面向对象所带来的好处。
查看各个集合的Iterator具体实现地址以下:
传送门一、http://blog.csdn.net/mazhimazh/article/details/17759579
传送门二、http://blog.csdn.net/mazhimazh/article/details/17835467
继续看Collection接口,源代码以下:
public interface Collection<E> extends Iterable<E> { // 查找操做 int size(); Iterator<E> iterator(); // 判断 boolean isEmpty(); boolean contains(Object o); boolean containsAll(Collection<?> c); // 增长操做 boolean add(E e); boolean addAll(Collection<? extends E> c); // 删除操做 boolean remove(Object o); boolean removeAll(Collection<?> c);// Removes all of this collection's elements that are also contained in the specified collection (optional operation). boolean retainAll(Collection<?> c);// Retains only the elements in this collection that are contained in the specified collection (optional operation). void clear(); // 集合转换 Object[] toArray(); <T> T[] toArray(T[] a); // 提供equals()和hashCode() boolean equals(Object o); int hashCode(); }
Collection接口针对集合定义了一些基本的操做,因此任何一个具体的集合实现类都有含有这些方法。可是因为抽象层次较高,因此通常一个具体 的集合实现类,如ArrayList、HashMap等都不会直接继承这个接口,而是继承这个接口的一些子类来实现。因此说每一个集合的具体实现类都直接或 间接继承了这个接口。
有一类重要的方法还须要说明一下:
boolean add(E e); boolean addAll(Collection<? extends E> c); boolean remove(Object o); boolean removeAll(Collection<?> c);
拿add(E e)方法来举例,这个方法将在集合中添加一个新的元素。方法会返回一个boolean,可是返回值不是表示添加成功与否。 仔细阅读doc能够看到,Collection规定:若是一个集合拒绝添加这个元素,不管任何缘由,都必须抛出异常。这个返回值表示的意义是add()方 法执行后,集合的内容是否改变了(就是元素有无数量,位置等变化),这是由具体类实现的。即:若是方法出错,总会抛出异常;返回值仅仅表示该方法执行后这 个Collection的内容有无变化。
观察发现传入的参数有许多都是Collection<?>类型的,这就为各个集合的具体实现类实现相互的操做提供了便利。举个例子:
LinkedList<String> list=new LinkedList<>(); list.add("xy"); list.add("mn"); Collection<String> ct=new HashSet<String>(); ct.add("abc"); ct.add("def"); ct.addAll(list); Iterator<String> iter=ct.iterator(); while(iter.hasNext()){ System.out.println(iter.next()); }
将LinkedList集合中的元素添加到HashSet中,只须要调用addAll()方法便可。最后结果输出以下:
mn
abc
def
xy
1 Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操做和属性。
Collection包含了List和Set两大分支。
(01) List是一个有序的队列,每个元素都有它的索引。第一个元素的索引值是0。
List的实现类有LinkedList, ArrayList, Vector, Stack。
(02) Set是一个不容许有重复元素的集合。
Set的实现类有HastSet和TreeSet。HashSet依赖于HashMap,它其实是经过HashMap实现的;TreeSet依赖于TreeMap,它其实是经过TreeMap实现的。
2 Map是一个映射接口,即key-value键值对。Map中的每个元素包含“一个key”和“key对应的value”。
AbstractMap是个抽象类,它实现了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是继承于AbstractMap。
Hashtable虽然继承于Dictionary,但它实现了Map接口。
接下来,再看Iterator。它是遍历集合的工具,即咱们一般经过Iterator迭代器来遍历集合。咱们说Collection依赖于Iterator,是由于Collection的实现类都要实现iterator()函数,返回一个Iterator对象。
ListIterator是专门为遍历List而存在的。
再看Enumeration,它是JDK 1.0引入的抽象类。做用和Iterator同样,也是遍历集合;可是Enumeration的功能要比Iterator少。在上面的框图 中,Enumeration只能在Hashtable, Vector, Stack中使用。
最后,看Arrays和Collections。它们是操做数组、集合的两个工具类。