【codejava】第八版:第十三章 集合[001] [20180104]

  △集合接口                              △算法
  △具体的集合*                                 △遗留的集合
  △集合框架 

13.1 集合接口
      java最初版本只为最常用的数据结构提供了很少的一组类,Vector,stack,hashtable,Bitset,Enumeration,其中的Enumeration接口提供了一种用于访问任意容器中各个元素的抽象机制,这是一种很明智的选择,但是想建立一个全面的集合类库还需要大量的事件和高超的技能.
      13.1.1 将集合的接口与实现分离 
        与现代的数据结构类库的常见情况一样,java集合类库也将接口(interface)与实现(implements)分离,首先看一下人们熟悉的数据结构--队列(queue)是如何分离的: 队列接口指出可以在队列的尾部添加元素,在队列的头部删除元素,并且可以查找队列中元素的个数,当需要收集对象,并按照“ 先进先出”的规则检索对象时就应该使用队列.一个队列接口的最小形式可能类似下面这样
interface Queue <E >{
     void add(E element);
    E remove();
     int size();
}
①    ②    ③    ④    ⑤
↑                      ↑
head(头部)                   tail(尾部)

这个接口并没有说明队列是如何实现的。队列通常有两种实现方式,一种是使用循环数组,另一种是使用链表,循环数组顾名思义就不解释啦,链表就是通过类似指针的方式前后指向并连接起来.

循环数组要比链表更高效,因此多数人优先选择循环数组,然后循环数组是一个有界集合,即容量有限,如果程序中要收集的对象数量没有上限,就最好使用链表来实现。
     在研究API文档时,会发现另外一组名字以Abstract开头的类,例如AbstractQueue.这些类是为了类库实现者而设计的。如果想要实现自己的队列类(也许不太可能),会发现扩展 AbstractQueue类要比实现Queue接口中的所有方法轻松得多。

13.1.2 JAVA类库中的集合接口和迭代器接口 除了这两个方法外,还有几个方法,将在稍后介绍。add方法用于向结合中添加元素,如果添加元素确实改变了集合就返回true
,如果集合没有发生变化就返回false。iterator方法用于返回一个实现了Iterator接口的对象,可以使用这个迭代器对象一次访问集合中的元素。
     1 、迭代器     Iterator接口包含3个方法:
public  interface Iterator <E > {   
     boolean hasNext(); 
    E next();
     void remove();
}
通过反复调用next()可以逐个访问集合中的每个元素,但是,如果到达了集合的末尾,next方法将抛出一个NoSuchElementException。因此需要在调用next()方法之前调用hasNext()方法。
        Collection <String > list  =  new ArrayList <String >();
        Iterator <String > itr  = list.iterator();
         while(itr.hasNext()){
            String str  = itr.next();
            ..........
        }
从java se5.0起,这个循环可以采用一种更优雅的缩写方式,用"for-each"循环可以更加
简练地表示同样的循环操作
        Collection <String > list  =  new ArrayList <String >();
         for(String str  : list){
            dosomething.........
        }
编译器简单地将“for each”循环翻译为带有迭代器的循环,他可以与任何实现了iterator接口的对象一起工作,这个接口只包含一个方法(这个是JDK1.6及以下了, 现在JDK1.8已经加入了两个方法, 大家可以去看一下, 接口里面支持编写实现方法了)
public  interface Iterable <T > {
     /**
     * Returns an iterator over a set of elements of type T.
     * 
     * @return an Iterator.
     */

    Iterator <T > iterator();
}
因为Collection接口扩展了Iterator接口,所以对于标准类库中的任何集合都可以使用"for  each"循环.
     元素被访问的顺序取决于集合类型如果对ArrayList进行迭代,迭代器将从索引0开始,每迭代一次索引增加1。然后,如果访问HashSet中的元素,每个元素将会按照某种随机的次序出现,虽然可以确定在迭代过程中能够遍历集合中的所有元素,但却无法预知元素被访问的次序,这对于计算总和或统计符合某个条件的元素个数这类与顺序无关的操作来说。不是什么问题。
      √注释:编程老手会注意到:Iterator接口的next和hasNext与Enumeration接口的nextElement和hasMoreElements方法的作用一样,java集合类库的设计者可以选择使用Enumeration接口,但是,他们不喜欢这个接口累赘的方法名,于是便引入了较短方法名的新接口。
    java集合类库中的迭代器与其他类库中的迭代器在概念上有着重要的区别。在传统的集合类库中,例如C++的标准模板库,迭代器是根据数组索引建模的。如果给定这样一个迭代器,就可以查看制定位置上的元素,就像知道数组索引i就可以查看数组元素a[i]一样,不需要查找元素,就可以将迭代器向前一个位置,这与不需要执行查找操作就可以通过i++将数组索引向前移动一样。 但java迭代器不是这样操作的,查找操作与位置变更时紧密相连的,查找一个元素为唯一方法是调用next,而在执行查找操作的同时,迭代器的位置随之向前移动因此,应该将java迭代器认为是位于两个元素之间,当调用next方法时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用.
     √注释: 这里还有一个有用的类推,可以将iterator.next与InputStream.read看做是等效的,从数据流中读取一个字节,就会自动滴“消耗掉”这个字节,下一次调用read将会消耗并返回输入的下一个字节,用同样的方式,反复地调用next就可以读取集合中的所有元素。

      2、删除元素  Iterator接口的remove方法将删除上次调用next方法时返回的元素。在大多数情况下,在决定删除某个元素之前应该先看一下这个元素是很具有实际意义的。然而,如果想删除指定位置上的元素,仍然需要越过这个元素,下面是如何删除字符串集合中第一个元素的方法
        Iterator <String > itr  = list.iterator();
        itr.next(); //skip over the first element 必须要先调用 next先越过要删除的元素
        itr.remove(); //now remove it
更重要的是,对next和remove方法的调用时相互依赖的。如果调用remove之前没有调用next将是不合法的.将会抛出一个IllegalStateException.
     
3、泛型实用方法    由于Collection与Iterator都是泛型接口,可以编写操作任何集合类型的实用方法。例如,下面是一个检测任何集合是否包含制定元素的泛型方法( 理解下面代码,为什么不需要进行强制类型转换:equals方法是继承的,所以比较的就是obj原始对象)
     public  static  <E >  boolean contains(Collection <E > list, Object obj){
         for(E element  : list){
             if(element.equals(obj))  return true;
        }
         return false;
    }

当然,如果实现Collection接口的每一个类都要提供如此多的例行方法将是一件很烦人的事情,为了能够让实现者更容易地实现这个接口,Java类库提供了一个类AbstractCollection,它将基础方法size和iterator抽象化了,但是在此提供了例行方法
public  abstract  class AbstractCollection <E >  implements Collection <E > {
     public  abstract Iterator <E > iterator();
     public  abstract  int size();
     public  boolean contains(Object o) {
    Iterator <E > e  = iterator();
     if (o ==null) {
         while (e.hasNext())
         if (e.next() ==null)
             return true;
    }  else {
         while (e.hasNext())
         if (o.equals(e.next()))
             return true;
    }
     return false;
    }
}
此时,一个具体的集合类可以扩展AbstractCollection类了,现在要由具体的集合类提供iterator方法,而contains方法已由AbstractCollection超类提供了。然而,如果子类有更加有效的方法实现contains方法,也可以由子类提供,就这点而言,没什么限制。






interface Queue <E >{
     void add(E element);
    E remove();
     int size();
}
①    ②    ③    ④    ⑤
↑                      ↑
head                   tail

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值