如果现在有一个Iterable类,你想要添加一种或多种在foreach语句中使用这个类的方法,例如方向迭代,应该怎么做呢? 如果之间继承这个类,并且覆盖iterator()方法,你只能替换现有的方法,而不能实现选择
一种解决方案是所谓的adapter方法的惯用法,"适配器"部分来自于设计模式,因为你必须提供特定接口以满足foreach语句,当你有一个接口并需要另一个接口时,编写adapter就可以解决问题,这里,希望在默认的前向迭代器的基础上,添加方向迭代器的能力,因此不能使用覆盖,而是添加了一个能够产生Iterable对象的方法,该对象可以用于foreach语句,正如你所见,可以提供多种使用foreach的方式
packageobject;//: holding/AdapterMethodIdiom.java//The "Adapter Method" idiom allows you to use foreach//with additional kinds of Iterables.
import java.util.*;class ReversibleArrayList extends ArrayList{public ReversibleArrayList(Collection c) { super(c); }public Iterablereversed() {//返回一个具有反向迭代器的Iterablereturn new Iterable() {public Iteratoriterator() {return new Iterator() {int current = size() - 1;public boolean hasNext() { return current > -1; }public T next() { return get(current--); }public void remove() { //Not implemented
throw newUnsupportedOperationException();
}
};
}
};
}
}public classAdapterMethodIdiom {public static voidmain(String[] args) {
ReversibleArrayList ral =
new ReversibleArrayList(
Arrays.asList("To be or not to be".split(" ")));//Grabs the ordinary iterator via iterator():
for(String s : ral)
System.out.print(s+ " ");
System.out.println();//Hand it the Iterable of your choice
for(String s : ral.reversed())
System.out.print(s+ " ");
}
}/*Output:
To be or not to be
be to not or be To*///:~
通过这种方法,可以在IterableClass.java的示例中添加两种适配器方法
packageobject;//: holding/MultiIterableClass.java//Adding several Adapter Methods.
import java.util.*;public class MultiIterableClass extendsIterableClass {public Iterablereversed() {return new Iterable() {public Iteratoriterator() {return new Iterator() {int current = words.length - 1;public boolean hasNext() { return current > -1; }public String next() { return words[current--]; }public void remove() { //Not implemented
throw newUnsupportedOperationException();
}
};
}
};
}public Iterablerandomized() {return new Iterable() {public Iteratoriterator() {
List shuffled =
new ArrayList(Arrays.asList(words));
Collections.shuffle(shuffled,new Random(47));
returnshuffled.iterator();
}
};
}public static voidmain(String[] args) {
MultiIterableClass mic= newMultiIterableClass();for(String s : mic.reversed())
System.out.print(s+ " ");
System.out.println();for(String s : mic.randomized())
System.out.print(s+ " ");
System.out.println();for(String s : mic)
System.out.print(s+ " ");
}
}/*Output:
banana-shaped. be to Earth the know we how is that And
is banana-shaped. Earth that how the be And we know to
And that is how we know the Earth to be banana-shaped.*///:~
Collections方法并没有打乱原来的数组,而是打乱了shuffled中的引用,之所以这样,只是因为,randmize()方法用一个ArrayList将Arrays.asList()结果包装了起来
如果这个有Arrays.asList()产生的List被直接打乱,那么就会修改底层是数组,就像下面这样;
packageobject;//: holding/ModifyingArraysAsList.java
import java.util.*;public classModifyingArraysAsList {public static voidmain(String[] args) {
Random rand= new Random(47);
Integer[] ia= { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List list1 =
new ArrayList(Arrays.asList(ia));//ia的输出被传给了ArrayList构造器,这将创建一个ia的元素引用的ArrayList
System.out.println("Before shuffling: " +list1);
Collections.shuffle(list1, rand);
System.out.println("After shuffling: " +list1);
System.out.println("array: " +Arrays.toString(ia));
List list2 = Arrays.asList(ia);//lsit2 直接使用Arrays.asList(ia),这样做会直接修改ia的数据
System.out.println("Before shuffling: " +list2);
Collections.shuffle(list2, rand);
System.out.println("After shuffling: " +list2);
System.out.println("array: " +Arrays.toString(ia));
}
}/*Output:
Before shuffling: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
After shuffling: [4, 6, 3, 1, 8, 7, 2, 5, 10, 9]
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Before shuffling: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
After shuffling: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8]
array: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8]*///:~
意识到Arrays.asLIst()产生的对象会使用底层数组作为其物理实现是很重要的,只要你执行的操作会修改这个List,并且你不想原来的数组被修改那么你就应该在另一个容器中创建副本