如何在Java中将迭代器实现为类的属性
假设我有这个简单的MyArray类,有两个简单的方法:add,delete和iterator。 在main方法中,我们可以看到它应该如何使用:
public class MyArray { int start; int end; int[] arr; myIterator it; public MyArray(){ this.start=0; this.end=0; this.arr=new int[500]; it=new myIterator(); } public void add(int el){ this.arr[this.end]=el; this.end++; } public void delete(){ this.arr[this.start]=0; this.start++; } public static void main(String[] args){ MyArray m=new MyArray(); m.add(3); m.add(299); m.add(19); m.add(27); while(m.it.hasNext()){ System.out.println(m.it.next()); } }
然后MyIterator应该以某种方式实现:
import java.util.Iterator; public class myIterator implements Iterator{ @Override public boolean hasNext() { // TODO Auto-generated method stub return false; } @Override public Object next() { // TODO Auto-generated method stub return null; } @Override public void remove() { // TODO Auto-generated method stub }
}
MyIterator应该从MyArray类迭代arr ,从开始到结束值; 两者都是MyArray的属性。 因此,由于MyIterator应该使用MyArray属性, MyIterator应该如何实现? 也许我可以在初始化中发送当前对象:
it=new myIterator(this);
但我想这不是最好的灵魂。 或者也许MyArray本身应该实现Iterator接口? 这是怎么解决的?
编辑:
好的,谢谢大家。 这是我想要做的一个简单的例子,所以不关心固定长度数组。 我真的想做的是循环FIFO,这就是为什么start
和end
都是游标。
该循环FIFO将是一对整数对的数组,例如,大小为300: int[][] arr=new int[300][2]
。
当迭代一个循环数组时,我必须小心,如果计数器到达终点并从头开始,所以这就是我解决它的方法:
if (this.start >= this.end ) temp_end=this.end+this.buff.length; else temp_end=this.end; int ii; int j=0; int[] value=new int[2]; for(int i=this.start; i<temp_end; i++){ ii=i% this.arr.length; value=this.buff[ii]; //do anything with value
}
但是我想避免担心这些事情并且只是以一种简单的方式迭代,我可以用迭代器接口来做这个,但后来我遇到了两个问题:第一个我已经解释过并且已经被很多答案解决了,第二个一个是我的数组由一对int组成,我不能使用原始类型的迭代器。
将迭代器维护为类的实例变量非常不寻常。 你只能遍历一次数组 – 可能不是你想要的。 更有可能的是,您希望您的类为想要遍历数组的任何人提供迭代器。 下面是一个更传统的迭代器。
Java 5+代码 – 我没有尝试编译或运行,因此它可能包含错误(现在不在dev机器附近)。 它还使用autobox’ing将Integer
转换为int
。
public class MyArray implements Iterable { public static class MyIterator implements Iterator { private final MyArray myArray; private int current; MyIterator(MyArray myArray) { this.myArray = myArray; this.current = myArray.start; } @Override public boolean hasNext() { return current < myArray.end; } @Override public Integer next() { if (! hasNext()) throw new NoSuchElementException(); return myArray.arr[current++]; } @Override public void remove() { // Choose exception or implementation: throw new OperationNotSupportedException(); // or //// if (! hasNext()) throw new NoSuchElementException(); //// if (currrent + 1 < myArray.end) { //// System.arraycopy(myArray.arr, current+1, myArray.arr, current, myArray.end - current-1); //// } //// myArray.end--; } } .... // Most of the rest of MyArray is the same except adding a new iterator method .... public Iterator iterator() { return new MyIterator(); } // The rest of MyArray is the same .... }
另请注意:请注意不要在静态数组上达到500元素限制。 如果可以,请考虑使用ArrayList类。
在我看来,最好将MyArray实现为常见的Iterable对象,因此可以在for语句中使用它。
我的建议:
/** * My array */ public class MyArray implements Iterable { /** * Internal used iterator. */ private class MyArrayIterator implements Iterator { private MyArray _array; /** * @param array The underlying array. */ public MyArrayIterator(MyArray array) { this._array = array; } /** * Gets the underlying array. * * @return The underlying array. */ public MyArray getArray() { return this._array; } @Override public boolean hasNext() { // TODO Auto-generated method stub return false; } @Override public TItem next() { // TODO Auto-generated method stub return null; } @Override public void remove() { // TODO Auto-generated method stub } } public void add(int el){ // do add } public void delete(){ // do delete } @Override public Iterator iterator() { // TODO Auto-generated method stub return new MyArrayIterator (this); } }
正如我所说,你可以在for语句中使用它:
private static void test(MyArray strArray) { for (String str: strArray) { // do something } }
迭代器是一个接口。 Iterator
表示只有Object可以到这里(E)。 Iterator
是合法的,但Integer
不是因为int是原始数据类型
您可以将数组更改为ArrayList ,然后遍历此arraylist。 我添加了getIterator()
方法,它返回arraylist.iterator()
并在main()
方法中测试它
import java.util.ArrayList; import java.util.Iterator; public class MyArray { int start; int end; ArrayList arr; public MyArray() { this.start = 0; this.end = 0; arr = new ArrayList (500); } public void add(int el) { arr.add(el); this.end++; } public void delete() { arr.remove(arr.size()-1); this.start++; } public Iterator getIterator(){ return arr.iterator(); } public static void main(String[] args) { MyArray m = new MyArray(); m.add(3); m.add(299); m.add(19); m.add(27); Iterator it = m.getIterator(); while(it.hasNext()){ System.out.println(it.next()); } } }
我的建议是让MyArray
实现接口java.lang.Iterable
并根据iterator()
调用创建迭代器的实例(作为匿名类)。 然后,您可以在foreach
构造中直接使用MyArray
的实例:
public class MyArray implements Iterable { // ... // Only arr is needed now as an instance variable. // int start; // int end; int[] arr; // myIterator it; /** * From interface Iterable. */ public Iterator iterator() { return new Iterator () { // The next array position to return int pos = 0; public boolean hasNext() { return pos < arr.length; } public Integer next() { if(hasNext()) return arr[pos++]; else throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); } } } }
更新:根据BertF的评论,我更新了我的代码以表明, MyArray
类的唯一实例变量现在是arr
。 迭代器的状态现在位于匿名Iterator
实现中。 因此,您可以创建多个不会相互干扰的迭代器实例。
编辑:这不适用于基本类型的数组:您可以使用数组:
it = new Arrays.asList(arr).subList(start, end).iterator();
编辑结束
如果你真的想要实现自己的迭代器,我建议在这种情况下使用内部类。 这样您就可以从myIterator访问MyArray.this。
public class MyArray { .... private class myIterator implements Iterator{ .... } }
MyArray应该实现Iterator,因为它还负责维护数组。 简单的封装原理。