1

我正在尝试为我自己的泛型类编写自己的迭代器。我一直在看几个 YouTube 教程并在网上搜索。

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Pair<T> implements Iterable<T> {

    private T left;
    private T right;

    public Pair(T left, T right){
        this.left = left;
        this.right = right;
    }

    public  T getRight(){return this.right;}
    public  T getLeft(){return this.left;}

    // own Iterator
    @Override
    public Iterator<T> iterator() {
        return new myIterator;
    }


    class myIterator implements Iterator<T>{
        T newLeft = null;

        @Override
        public boolean hasNext() {
            if(newLeft == null && Pair.getLeft() != null){
                return true;
            }
            else if(newLeft !=null){
                return Pair.getRight() !=null;
            }
            else {
                return false;
            }
        }
        @Override
        public T next() {
            if(newLeft == null && Pair.getLeft() != null){
                newLeft = Pair.getLeft();
                return newLeft;
            }
            else if(newLeft != null){
                T newRight = Pair.getLeft();
                newLeft = Pair.getRight();
                return newRight;
            }
            throw new NoSuchElementException();
        }
    }
}

IntelliJ 指出的问题是,我不能按照我尝试的方式在 Iterator-Class 中使用 getLeft 和 getRight ,因为不能从静态上下文中引用非静态方法。我一直在研究静态等等,但无法解决这个问题。我是完全走错了路,还是我的方法至少有点接近?

更新

运行时:

public static void main(String[] args) {
        Pair<Integer> intPair= new Pair(5,1);
        Pair<String> stringPair=new Pair("foo", "bar");

        Iterator<Integer> itr= intPair.iterator();
        while(itr.hasNext()){
            System.out.println(itr.next());
        }
    }

我遇到了一个无限循环,打印 5。所以,Iterator 本身可以工作,但是我的方法有一个逻辑错误。正在努力,但我感谢任何输入。:)

更新2

发现逻辑错误:NewLeft 从未更改为 null。努力解决它。

更新3

: 解决了!具有嵌入式迭代器类和主类的完整对类,调用如下:

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Pair<T> implements Iterable<T> {

    private T left;
    private T right;

    public Pair(T left, T right){
        this.left = left;
        this.right = right;
    }

    public  T getRight(){return this.right;}
    public  T getLeft(){return this.left;}

    // size of a pair is always 2
    public int size =2;

    // own Iterator
    @Override
    public Iterator<T> iterator() {
        return new myIterator();
    }

    // embedded iterator class
    public class myIterator implements Iterator<T>{
        T newLeft = null;
        T newRight = null;

        @Override
        public boolean hasNext() {
            if(newLeft == null && getLeft() != null){
                return true;
            }
            else if(newLeft !=null && newRight == null){
                newRight=getRight();
                return getRight() !=null;
            }
            else {
                return false;
            }
        }
        @Override
        public T next() {
            if(newLeft == null && getLeft() != null){
                newLeft = getLeft();
                return newLeft;
            }
            else if(newLeft != null && getRight() != null){
                newRight = getRight();
                return newRight;
            }
            throw new NoSuchElementException();
        }
    }
}

主要的:

import java.util.Iterator;

public class main {

    public static void main(String[] args) {
        Pair<Integer> intPair= new Pair(5,1);
        Pair<String> stringPair=new Pair("foo", "bar");

        Iterator<Integer> itr= intPair.iterator();
        while(itr.hasNext()){
            System.out.println(itr.next());
        }

        Iterator<String> itrS= stringPair.iterator();
        while(itrS.hasNext()){
            System.out.println(itrS.next());
        }
    }
}

谢谢大家,谁帮助,你把我带到了这个解决方案:)

4

2 回答 2

2

您的初始代码正在定义一个变量T newLeft,其唯一目的是跟踪左值是否已被消耗,由非null值指示。使用变量会更清楚boolean,即boolean hasSeenLeft;在这里。然后,很明显这个类是不完整的,因为它没有跟踪是否已经消耗了正确的值。

在您的固定代码中,您有newLeftand newRight,它解决了问题,但仍然具有误导性,因为它们的名称和类型都没有表明实际目的。如果将它们更改为boolean变量,则可以设计它们以指示是否存在未决值,例如

final class myIterator implements Iterator<T> { // no need to make this public
    boolean hasPendingLeft = getLeft() != null, hasPendingRight = getRight() != null;

    @Override
    public boolean hasNext() {
        return hasPendingLeft || hasPendingRight;
    }

    @Override
    public T next() {
        if(hasPendingLeft) {
            hasPendingLeft = false;
            return getLeft();
        }
        else if(hasPendingRight) {
            hasPendingRight = false;
            return getRight();
        }
        throw new NoSuchElementException();
    }
}

这更简单,更具可读性。

请注意,这两种解决方案都无法处理中间更改,但是Pair无论如何,此类看起来在最好的情况下应该是不可变的。在这种情况下,值得将leftand声明rightfinal.

对于可变类,值得为中间修改添加快速失败行为,类似于 Collection API:

final class myIterator implements Iterator<T> { // no need to make this public
    boolean hasPendingLeft = getLeft() != null, hasPendingRight = getRight() != null;

    @Override
    public boolean hasNext() {
        return hasPendingLeft || hasPendingRight;
    }

    @Override
    public T next() {
        if(hasPendingLeft) {
            hasPendingLeft = false;
            T left = getLeft();
            if(left == null) throw new ConcurrentModificationException();
            return left;
        }
        else if(hasPendingRight) {
            hasPendingRight = false;
            T right = getRight();
            if(right == null) throw new ConcurrentModificationException();
            return right;
        }
        throw new NoSuchElementException();
    }
}

null所以即使在错误的情况下,这仍然保证非值,并且会抛出一个更有意义的异常。

于 2018-07-05T12:10:25.910 回答
1

我猜你想迭代这对中的 0 到 2 个可能的值?在您的迭代器中,您应该引用 T 的实例。您收到的消息是因为您试图以静态方式调用 Pair 中的方法(即,当 Pair 是班级)

于 2018-07-05T10:17:35.573 回答