1. 程式人生 > >【Java程式設計】foreach支援集合、Collection、Iterable遍歷原因分析

【Java程式設計】foreach支援集合、Collection、Iterable遍歷原因分析

1、Collection、AbstractCollection、Iterable關係

Iterator是一個介面
public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}
Iterable是一個介面
public interface Iterable<T> {
    Iterator<T> iterator();
}
AbstractCollection抽象類實現了Collection介面
public abstract class AbstractCollection implements Collection {}
Collection介面繼承了Iterable介面
public interface Collection extends Iterable{}
關係圖如下:


分析:

1、foreach迴圈支援對Iterable類(實現了Iterable介面)的遍歷,該結論在本blog第3節得到論證; 2、Collection介面繼承Iterable介面,foreach支援對實現了Collection介面例項類(ArrayList,LinkedList,HashSet,TreeSet,LinkedHashSet)的遍歷,該結論已在《【Java程式設計】Foreach對陣列、Collection物件、Iterable物件》
得到論證; 3、Collection介面繼承Iterable介面,AbstractCollection抽象類實現了Collection介面,foreach支援使用繼承AbstractCollection類建立Collection實現類的遍歷,該結論在本blog第2點得到論證;

2、使用繼承AbstractCollection類來建立一個Collection的實現(該Collection實現類支援foreach遍歷)

你要實現一個不是Collection的外部類時,由於讓它去實現Collection介面可能非常困難,此時使用AbstractCollection就會變得相當吸引人;AbstractCollection提供了Collection的預設實現,使得你可以建立AbstractCollection的子類,而其中沒有不必要的程式碼重複,不過繼承AbstractCollection來實現Collection需要強制實現iterator()和size(),以便提供AbstractCollection沒有實現但是AbstractCollection中的其他方法會使用的方法;

package com.andieguo.iterabledemo;

import java.util.AbstractCollection;

import java.util.Iterator;

import com.andieguo.collectiondemo.Book;


public class CollectionSequence<T> extends AbstractCollection<T> {
	private T[] array = null;
	
	public CollectionSequence(T[] t){
		this.array = t ;
	}
	@Override
	public Iterator<T> iterator() {
		// TODO Auto-generated method stub
		return new Iterator<T>(){
			private int index = 0; 
			@Override
			public boolean hasNext() {
				// TODO Auto-generated method stub
				return index < array.length;
			}

			@Override
			public T next() {
				// TODO Auto-generated method stub
				return array[index++];
			}

			@Override
			public void remove() {
				// TODO Auto-generated method stub
				throw new UnsupportedOperationException();
			}};
	}

	@Override
	public int size() {
		// TODO Auto-generated method stub
		return array.length;
	}

	public static void main(String[] args) {
		printObject(new String[]{"HELLO","EVERYBODY","WELCOME"});
		printObject(new Integer[]{1,2,3,4,5,6});
		printObject(new Book[]{new Book("數學"),new Book("英語")});
	}

	public static void printObject(Object[] t) {
		System.out.println("-------------使用foreach輸出-----------------");
		CollectionSequence<Object> cs = new CollectionSequence<Object>(t);
		for(Object object:cs){
			System.out.print(object+" ");
		}
		System.out.println("\n-----------使用iterator輸出----------------");
		Iterator<Object> it = cs.iterator();
		while(it.hasNext()){
			System.out.print(it.next()+" ");
		}
		System.out.println();
	}
}

3、使用實現Iterable介面來實現適用於foreach遍歷的自定義類。

Java SE5引入了Iterable介面,該介面包含一個能夠產生Iterator的iterator()方法,並且Iterable介面被foreach用來在序列中移動。因此你建立了任何實現Iterable的自定義類,都可以將它用於foreach語句中。

package com.andieguo.iterabledemo;

import java.util.Iterator;

public class IterablerClass<T> implements Iterable<T>{
	private T[] array = null;
	
	public IterablerClass(T[] t){
		this.array = t ;
	}
	@Override
	public Iterator<T> iterator() {
		// TODO Auto-generated method stub
		return new Iterator<T>() {
			private Integer index = 0;
			@Override
			public boolean hasNext() {
				// TODO Auto-generated method stub
				return index<array.length;
			}

			@Override
			public T next() {
				// TODO Auto-generated method stub
				return array[index++];
			}

			@Override
			public void remove() {
				// TODO Auto-generated method stub
			}
		};
	}
	public static void main(String[] args) {
		IterablerClass<String> iterablerClass = new IterablerClass<String>(new String[]{"武漢","深圳","上海","北京","重慶"});
		System.out.println("-------------使用foreach輸出-----------------");
		for(String s:iterablerClass){
			System.out.print(s+" ");
		}
		System.out.println("\n-----------使用iterator輸出----------------");
		Iterator<String> it = iterablerClass.iterator();
		while(it.hasNext()){
			System.out.print(it.next()+" ");
		}
	}
}

4、使用介面卡設計模式為Iteratable類(實現了Iterable介面)新增更多的遍歷方法。

如果你現有一個Iteratable類(實現了Iterable介面),你想要新增一種或多種在foreach語句中使用這個類的方法,如果直接繼承這個類,並覆蓋iterator()方法,你只能替代現有的方法,不能實現選擇。一種解決方案是使用介面卡設計模式,當我們有一個介面並需要另外一個介面時,編寫介面卡可以輕鬆解決問題。這裡我們希望在預設向前迭代的基礎上,新增產生反向迭代的能力,只需新增一個能夠產生Iterable物件的方法,該物件可以用於foreach語句。

package com.andieguo.iterabledemo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;

public class ReversibleArrayList<T> extends ArrayList<T> {
	private static final long serialVersionUID = 2843552489593809340L;

	public ReversibleArrayList(Collection<T> c){
		super(c);
	}
	/**
	 * 注意區別new Iterable<T>方法與new Iterator<T>()方法
	 * 使用Iterable能夠適用於foreach。使用Iterator能適用於while迴圈迭代
	 * @return
	 */
	public Iterable<T> reversed(){
		return new Iterable<T>(){
			@Override
			public Iterator<T> iterator() {
				// TODO Auto-generated method stub
				return new Iterator<T>() {
					int current = size()-1;//size()是父類ArrayList裡的方法
					@Override
					public boolean hasNext() {
						// TODO Auto-generated method stub
						return current > -1;
					}

					@Override
					public T next() {
						// TODO Auto-generated method stub
						return get(current--);
					}

					@Override
					public void remove() {
						// TODO Auto-generated method stub
						throw new UnsupportedOperationException();
					}
				};
			}};
	}
	
	public static void main(String[] args) {
		ReversibleArrayList<String> ral = new ReversibleArrayList<String>(Arrays.asList("one two three four five six".split(" ")));
		for(String str:ral){
			System.out.print(str+" ");
		}
		System.out.println();
		for(String str:ral.reversed()){
			System.out.print(str+" ");
		}
	}
}

5、參考文獻:

《Java程式設計思想(美)Bruce Eckel著 陳昊鵬 譯 第4版》