Java编程思想---第十一章 持有对象(下)

第十一章 持有对象(下)

11.12 CollectionIterator

 

  Collection是描述所有序列容器的共性的根接口,它可能会被仍为是一个附属接口,因为要表示其他若干个接口的共性而出现的接口。另外,java.util.AbstractCollection类提供了Collection的默认实现,使得我们可以创建AbstractCollection的子类型,而其中没有不必要的代码重复。

  使用接口描述的一个理由就是它可以使我们能够创建更通用的代码,通过针对接口而非具体实现来编写代码,我们的代码可以应用于更多的对象类型。因此,如果我编写的方法将接受一个Collection,那么该方法就可以应用于任何实现了Collection的类。

  当你要实现一个不是Collection的外部类时,由于让它去实现Collection接口可能非常困难或麻烦,因此使用Iterator就会变得非常吸引人。例如我们通过继承一个持有Pet对象的类来创建一个Collection的实现,那么我们必须实现所有的Collection方法,即使我们在display()方法中不必使用它们,也必须如此如此。尽管这可以通过继承AbstractCollection很容易的实现,但你无论如何还是要被强制实现iteratorsize(),以便提供AbstractCollection没有实现,但是AbstractCollection中的其他方法会使用到的方法。

 

11.13 Foreach与迭代器

 

  到目前为止,foreach语法主要用于数组,但是它也可以应用于任何Collection对象,我们实际上已经看过很多使用ArrayList时用到它的示例,下面是一个更通用的证明:

 

import java.util.*;

public class ForEachCollections {
    public static void main(String[] args) {
        Collection<String> cs = new LinkedList<String>();
        Collections.addAll(cs,"Take the long way home".split(" "));

        for(String s : cs)
            System.out.print("'" + s + "' ");
    }
}

 

输出结果为:

'Take' 'the' 'long' 'way' 'home'

 

  由于cs是一个Collection,所以这段代码展示了能够与foreach一起工作是所有Collection对象的特性。

  之所以能够工作,是因为Java SE5 引入了新的被称为Iterable的接口,该接口包含一个能够产生Iteratoriterator()方法,并且Iterable接口被foreach用来在序列中移动,因此如果你创建了任何实现Iterable的类,都可以将它用于foreach语句中:

 

import java.util.*;

public class IterableClass implements Iterable<String> {
    protected String[] words = ("And that is how " + "we know the Earth to be banana-shaped.").split(" ");
    public Iterator<String> iterator() {
        return new Iterator<String>() {
            private int index = 0;
            public boolean hasNext() {
                return index < words.length;
            }

            public String next() {
                return words[index++];
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
 
    public static void main(String[] args) {
        for(String s : new IterableClass())
            System.out.print(s + " ");
    }
}

 

输出结果为:

And that is how we know the Earth to be banana-shaped.

 

  iterator()方法返回的是实现了Iterator<String>的匿名内部类的实例,该匿名内部类可以遍历数组中所有单词,在main()中可以看到IterableClass确实可以用于foreach语句中。

 

11.13.1 适配器方法惯用类

 

  如果现在有一个Iterable类,你想要添加一种或多种在foreach语句中使用这个类的方法,应该怎么做?例如,假设你希望可以选择以向前的方向或者是向后的方向迭代一个单词列表,如果直接继承这个类,并覆盖iterator()方法,你只能替换现有的方法,而不能实现选择。

  一种解决方案是所谓适配器方法的惯用法,适配器部分来自于设计模式,因为你必须提供特定接口以满足foreach语句。当你有一个接口并需要另一个接口时,编写适配器就可以解决问题:

 

import java.util.*;

class ReversibleArrayList<T> extends ArrayList<T> {
    public ReversibleArrayList(Collection<T> c){
        super(c);
    }

    public Iterable<T> reversed() {
        return new Iterable<T>() {
            public Iterator<T> iterator() {
                return new Iterator<T>() {
                    int current = size() - 1;
                    public boolean hasNext() {
                        return current > -1;
                    }

                    public T next() {
                        return get(current--);
                    }

                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }
}

public class AdapterMethodIdiom {
    public static void main(String[] args) {
        ReversibleArrayList<String> ral = new ReversibleArrayList<>(Arrays.asList("To be or not to be".split(" ")));
        for (String s : ral)
            System.out.print(s + " ");
        System.out.println();
        for (String s : ral.reversed())
            System.out.print(s + " ");
    }

 

输出结果为:

To be or not to be

be to not or be To 

posted @ 2019-09-21 14:43  寓言i  阅读(169)  评论(0编辑  收藏  举报