如何在 java 中一个接一个地遍历两个不同类型的泛型列表?

How to iterate through two generic lists with different types one item after another in java?

我想创建一个迭代器 class,它允许我逐项迭代具有泛型类型(例如 lst1 整数、lst2 字符串)的列表。 为此,我必须考虑以下给定情况。

该接口是一个通用迭代器。这部分代码不能修改。

interface Iterator<E> {
E next ();
boolean hasNext();
}

列表class也定义如下。最重要的是,一个列表对象可以 return 一个带有方法 getIterator() 的迭代器对象。这部分代码不能修改。

class List<T> {
class ListNode {
    T val;
    ListNode next;

    ListNode (T v) {
        val = v; next = null;
    }
}

ListNode head;

List (ListNode hd) { head = hd; }
List () { this(null); }

void prepend (T val) {
    ListNode p = new ListNode(val);
    p.next = head;
    head = p;
}

//some other methods

class ListIterator implements Iterator<T> {
    ListNode pos;

    ListIterator () {
        pos = head;
    }

    public T next () {       
        T res = pos.val;
        pos = pos.next;
        return res;
    }

    public boolean hasNext () {
        return pos != null;
    }
}

Iterator<T> getIterator () {        
    return this.new ListIterator();
}
}

让我们假设两个列表具有相同的类型并且现在它们也具有相同的长度。我尝试用两个迭代器对象创建一个 class 并使用迭代器对象的方法来实现接口 Iterator。这部分代码是我创建的,可以修改。

class ZipIterator<T> implements Iterator<T>
{
int counter;
Iterator<T> first;
Iterator<T> second;

ZipIterator (Iterator<T> f, Iterator<T> s)
{
    first = f;
    second = s;
    counter = 0;
}

public T next ()
{
    if (counter % 2 == 0)
    {
        counter++;
        return first.next();
    }

    else
    {
        counter++;
        return second.next();
    }

}
public boolean hasNext ()
{
    if (counter % 2 == 0)
        return first.hasNext();
    else
        return second.hasNext();
}
}

这适用于两个相同类型的列表。这是我用于测试的代码和输出:

class IteratorUtils
{
public static void main (String[] args)
{
    List<Integer> lst1 = new List<>();
    List<Integer> lst2 = new List<>();
    lst1.prepend(3);
    lst1.prepend(2);
    lst1.prepend(1);
    lst2.prepend(8);
    lst2.prepend(9);
    lst2.prepend(10);
    Iterator<Integer> it1 = lst1.getIterator();
    Iterator<Integer> it2 = lst2.getIterator();
    ZipIterator<Integer> zit = new ZipIterator<>(it1, it2);
    while (zit.hasNext())
    {
        System.out.println(zit.next());
    }
}
}

输出:

1
10
2
9
3
8

现在我想以通用方式实现 ZipIterator,这样我就可以使用两个包含不同类型项目(例如整数和字符串)的列表。我知道我必须更改 class ZipIterator,以便 next() return 方法成为通用类型,但我不知道如何更改。 这是我必须完成的一项大学任务,教授已经留下了提示 "use wild cards like: ? extends T, ? super T, ? extends Object"。但是对于通配符,我只能指定继承或反对继承方向的类型,对吗?是否可以这样更改 ZipIterator class 以便它接受两个不同类型的迭代器对象?

我不会给出完整的解决方案(并且根据您的努力判断您不想要它),但我会尝试以一种让您自己找到它的方式进行解释。

首先是一个不相关的说明:您正在指定一个特定的迭代顺序。我认为这很好,我不会碰它。

你的教授给了你使用有界泛型的提示。让我们了解为什么需要它们(另请参阅 tutorial here and/or here)。如果您被要求编写一个接受 2 种未知类型中的任何一种参数的方法,您的解决方案是找到并接受它们的公共 superclass - Object.

在泛型中情况类似 - 找到最常见的分母,只是语法有点棘手。如果你要写构造函数

ZipIterator(Iterator<Object> f, Iterator<Object> s) {...}

并尝试初始化

List<Integer> lst1 = new List<>();
List<String> lst2 = new List<>();
new ZipIterator(it1, it2);

你会得到一个编译错误(读它)。这是因为 List<String> 不是 List<Object>,即使 StringObject。正确的做法是

ZipIterator(Iterator<? extends Object> f, Iterator<? extends Object> s) {...}

其中 ? extends Object 表示 "any type that extends Object"(这是全部,因为 Object...)。

所以你有构造函数,你需要对你的 class 进行更改以适应它。你甚至不需要实现给定的 Iterator<E>,你只需像你已经做的那样持有其中的 2 个。最后,class 本身不需要泛型:因为它的 next 方法必须能够 return 任何类型,所以它总是 returns Object

如果您在以后尝试解决此问题时有任何疑问,或者您发现此解决方案不符合作业要求,请随时 post 发表评论。

I know I have to change the class ZipIterator so the method next() returns a generic type but I don't know how.

这不太正确。由于 ZipIterator<T> 扩展了 Iterator<T>,它的 next() 方法必须 return T 实际上是一成不变的。这是有道理的:迭代器类型参数的全部意义在于让您指定其 next() 方法将 return.

的类型

相反,您的教授想要的只是能够从两个具有不同类型参数的迭代器构造一个ZipIterator<...>。例如,他希望能够写:

List<Integer> listOfIntegers = ...;
List<String> listOfStrings = ...;

ZipIterator<Object> zipIterator =
    new ZipIterator<>(listOfIntegers.getIterator(), listOfStrings.getIterator());

请注意,由于 zipIterator.next() 有时会 return 一个 Integer,有时 String,我们必须使用类似 ZipIterator<Object> 的东西来允许对于这两种可能性。其他选项包括 ZipIterator<Serializable>ZipIterator<Comparable<?>>,因为 Integer-s 和 String-s 都是 Serializable 并且都是 Comparable<?>.


所以您的教授希望您解决的问题是,在您当前的代码中,您的 构造函数 要求两个迭代器具有完全相同的类型参数(彼此相同,并且作为 ZipIterator 本身):

ZipIterator (Iterator<T> f, Iterator<T> s)

你知道如何解决这个问题吗?

据我了解,您想遍历不同类型的列表,其中一种解决方案是让您的构造函数接受迭代器满足要求,即它是任何扩展对象的迭代器,但这将限制您对检索到的项目的使用仅将其用作对象,否则您将不得不强制转换它们以实现进一步的任务,一种限制较少的方法是使构造函数接受迭代器满足这样的要求,即它是任何扩展最近共同祖先的事物的迭代器 ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s) 所以你的 class 看起来像这样

class ZipIterator<T> implements Iterator<T> {

    int counter;
    Iterator<? extends T> first;
    Iterator<? extends T> second;

    ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s) {
        first = f;
        second = s;
        counter = 0;
    }

    @Override
    public T next() {
        if (counter % 2 == 0) {
            counter++;
            return first.next();
        } else {
            counter++;
            return second.next();
        }
    }

    @Override
    public boolean hasNext() {
        if (counter % 2 == 0) {
            return first.hasNext();
        } else {
            return second.hasNext();
        }
    }

}

然后使用它你可以指定最合适的超级 class 两种类型都收敛到它,如果它是 Object 你可以写 ZipIterator<Object> zit = ,下面的代码将向您展示一个任意用例

        List<StringBuilder> bl= Arrays.asList(new StringBuilder("hi i'm builder"));
        List<String> sl = Arrays.asList("hi i'm string");
        ZipIterator<CharSequence> zit = new ZipIterator<>(bl.iterator(), sl.iterator());
        while (zit.hasNext()) {
            CharSequence cs = zit.next();
            System.out.println(cs.subSequence(6,cs.length()));
        }

感谢您的帮助。我学到了很多。这是我的解决方案和对任务的更多解释。

首先请注意,ZipIterator class 的设计并非一成​​不变。 ZipIterator 是我设计的。可能还有其他解决方案,但这是我的尝试。

指定任务:"Please construct a class IteratorUtils with several methods. The method zip receives two iterator objects and returns one iterator object, which iterates alternating through the items of the two received iterator objects. The iterator returned by the zip function should stop after the last item of the shorter iterator object. Use wildcards so you can apply the zip function to diffrent types of iterator objects."

为此,我首先创建了 class IteratorUtils。请注意,zip 功能的设计也不是一成不变的。在任务中它只说:"The method zip receives two iterator objects and returns one iterator object, which iterates alternating through the items of the two received iterator objects."

class IteratorUtils
{
static ZipIterator zip (Iterator<? extends Object> first, Iterator<? extends Object> second)
{
    return new ZipIterator(first, second);
}
}

然后我创建了 class ZipIterator。阅读您的答案和一些教程后,我理解了此任务中有界类型参数的含义。正如 user1803551 所说,ZipIterator class 不应该是通用的。我只需要意识到我必须找到常见的 superclass(这里是对象)。所以我不得不将 ZipIterator class 更改为以下内容:

class ZipIterator
{
int counter;
Iterator first;
Iterator second;

ZipIterator (Iterator<? extends Object> f, Iterator<? extends Object> s)
{
    first = f;
    second = s;
    counter = 0;
}

public Object next ()
{
    if (counter % 2 == 0)
    {
        counter++;
        return first.next();
    }

    else
    {
        counter++;
        return second.next();
    }

}

public boolean hasNext ()
{
    if (counter % 2 == 0)
        return first.hasNext();
    else
        return second.hasNext();
}
}

在我的主要方法中,我使用了以下代码:

public static void main (String[] args)
{
    List<Integer> lst1 = new List<>();
    List<String> lst2 = new List<>();
    lst1.prepend(3);
    lst1.prepend(2);
    lst1.prepend(1);
    lst2.prepend("three");
    lst2.prepend("two");
    lst2.prepend("one");
    Iterator<Integer> it1 = lst1.getIterator();
    Iterator<String> it2 = lst2.getIterator();
    ZipIterator zit = zip(it1, it2);
    while (zit.hasNext())
    {
        System.out.println(zit.next());
    }
}

输出:

1
one
2
two
3
three