假设我有这个简单的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 ,从 start 到 end 值;两者都是 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组成,我不能使用原始类型的迭代器。
答案 0 :(得分:8)
将迭代器维护为类的实例变量非常不寻常。您只能遍历数组一次 - 可能不是您想要的。更有可能的是,您希望您的类为想要遍历数组的任何人提供迭代器。下面是一个更传统的迭代器。
Java 5+代码 - 我没有尝试编译或运行,因此它可能包含错误(现在不在dev机器附近)。它还使用autobox'ing将Integer
转换为int
。
public class MyArray implements Iterable<Integer> {
public static class MyIterator implements Iterator<Integer> {
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<Integer> iterator() {
return new MyIterator();
}
// The rest of MyArray is the same ....
}
另请注意:请注意不要在静态阵列上达到500元素限制。如果可以,请考虑使用ArrayList类。
答案 1 :(得分:4)
在我看来,最好将MyArray实现为通用Iterable对象,因此可以在for语句中使用它。
我的建议:
/**
* My array
*/
public class MyArray<TItem> implements Iterable<TItem>
{
/**
* Internal used iterator.
*/
private class MyArrayIterator<TItem> implements Iterator<TItem>
{
private MyArray<TItem> _array;
/**
* @param array The underlying array.
*/
public MyArrayIterator(MyArray<TItem> array)
{
this._array = array;
}
/**
* Gets the underlying array.
*
* @return The underlying array.
*/
public MyArray<TItem> 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<TItem> iterator() {
// TODO Auto-generated method stub
return new MyArrayIterator<TItem>(this);
}
}
正如我所说,你可以在for语句中使用它:
private static void test(MyArray<String> strArray)
{
for (String str: strArray) {
// do something
}
}
答案 2 :(得分:2)
Iterator是一个界面。 Iterator<E>
表示仅对象可以到此处(E)。
Iterator<Integer>
是合法的,但Integer<int>
不是因为int是原始数据类型
您可以将数组更改为ArrayList,然后遍历此arraylist。我添加了getIterator()
方法,该方法返回arraylist.iterator()
并在main()
方法中对其进行测试
import java.util.ArrayList;
import java.util.Iterator;
public class MyArray {
int start;
int end;
ArrayList<Integer> arr;
public MyArray() {
this.start = 0;
this.end = 0;
arr = new ArrayList<Integer>(500);
}
public void add(int el) {
arr.add(el);
this.end++;
}
public void delete() {
arr.remove(arr.size()-1);
this.start++;
}
public Iterator<Integer> 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<Integer> it = m.getIterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
答案 3 :(得分:2)
我的建议是让MyArray
实现接口java.lang.Iterable
并根据iterator()
调用创建一个迭代器实例(作为匿名类)。然后,您可以直接在MyArray
构造中使用foreach
的实例:
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<Integer> iterator() {
return new Iterator<Integer>() {
// 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
实现中。因此,您可以创建多个不会相互干扰的迭代器实例。
答案 4 :(得分:1)
编辑:这对基本类型的数组不起作用: 你可以使用Arrays:
it = new Arrays.asList(arr).subList(start, end).iterator();
结束编辑
如果你真的想要实现自己的迭代器,我建议在这个场景中使用内部类。这样您就可以从myIterator访问MyArray.this。
public class MyArray {
....
private class myIterator implements Iterator{
....
}
}
答案 5 :(得分:0)
MyArray应该实现Iterator,因为它还负责维护数组。简单的封装原则。