2016-08-13 94 views
6

我想创建一个迭代器类,它允许我通过泛型类型(例如lst1整数,lst2字符串)列表遍历一个接一个的项目。 为此,我必须考虑以下给出的情况。如何在Java中迭代通过两个不同类型的一个接一个项目的通用列表?

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

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

列表类也定义如下。最重要的是,一个列表对象可以用方法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 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在一个通用的方法,这样我就可以使用两个不同类型的列表项目(例如整数和字符串)。我知道我必须更改ZipIterator类,以便方法next()返回一个泛型类型,但我不知道如何。 这是一个我必须做的大学任务,教授留下了一个提示:“使用通配符:?扩展T,?超级T,?扩展对象”。但对于通配符,我只能指定继承方向的类型,对吗?这可能改变ZipIterator类的方式,因此它接受两个不同类型的迭代器对象?

+0

是否有对任何约束两种类型?如果没有,你可以做的最好的就是返回Object。 –

+0

您发布的哪部分代码是您在作业中给定的部分,您可以修改哪部分? – user1803551

+0

好吧,我可以给出答案,但这会消除作业的所有困难。我可以给出一个提示,看看[PECS](http://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super)。 –

回答

3

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

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

你的教授给你提供了使用有界的泛型的提示。让我们来了解为什么需要它们(另请参阅tutorial here和/或here)。如果你被要求编写一个方法来接受2个未知类型的任何一个参数,你的解决方案是找到并使用它们的公共超类 - 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手段(这是所有的人都因为Object ...)“扩展Object任何类型”。

所以你有构造函数,你需要修改你的类来适应它。你甚至不需要实现给定的Iterator<E>,你只需要拥有2个像你已经做的那些。最后,类本身不需要泛型:因为它的next方法必须能够返回任何类型,它总是返回Object

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

0

我知道我必须改变ZipIterator类,所以方法next()返回一个泛型类型,但我不知道如何。

这并不完全正确。由于ZipIterator<T>延伸至Iterator<T>,因此其实next()方法必须返回T。这是有道理的:迭代器的类型参数的整个点是让你指定它的方法将返回的类型。

相反,您所有的教授都希望能够从两个具有不同类型参数的迭代器中获得构造 a ZipIterator<...>。例如,他(她)希望能够写:

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

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

需要注意的是,由于zipIterator.next()有时会返回一个Integer,有时一个String,我们不得不去的东西,如ZipIterator<Object>允许这两种可能性。其他选项包括ZipIterator<Serializable>ZipIterator<Comparable<?>>,因为Integer-s和String-s都是SerializableComparable<?>


让你的教授要你解决的问题是,在当前的代码,你构造既需要迭代器具有完全相同的类型参数(如对方,并为ZipIterator本身):

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

你看到如何解决这个问题吗?

+0

阅读对问题的评论。你最初的假设并不准确。 – user1803551

+0

@ user1803551:我确实阅读了评论,并支持我的“假设”。 '实现迭代器'对于设计是必不可少的,我们不应该因为教授把它留给学生写下来而抛弃它。也许学生可以找到一个“简单的出路”,放弃这一点,并对作业进行部分评分,但为什么你会鼓励呢? – ruakh

+0

如果是设计,那么它不是“石头” - 这是一个选择。我不明白你为什么认为不实施它会导致部分信用。我们没有关于分级方法或任何特定要求的信息。我也不明白为什么放弃它是一个“简单的出路”,如果没有必要,那么放弃它是正确的选择。如果有的话,教授暗示在解决方案中使用通配符。 – user1803551

0

据我所知,你想遍历不同类型的列表解决方案之一是让你的构造函数接受迭代器满足要求,它是任何事物的迭代器扩展对象,但这会限制你使用检索到的项目只是用它作为对象,或者你必须将它们转换为实现更多的任务一个较少限制性的方法是使构造函数接受迭代器满足要求它是任何事物的迭代器,扩展了最近的共同祖先,就像这样ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s)所以你的类将会看起来是这样的

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(); 
     } 
    } 

} 

然后使用它,你可以指定最合适的超类,两种类型收敛t ·其,在它是案件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())); 
     } 
0

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

请注意,首先,ZipIterator类的设计不是一成不变的。 ZipIterator是我设计的。可能有另一种解决方案,但这是我的尝试。

要指定任务:“请使用几种方法构造一个IteratorUtils类,方法zip接收两个迭代器对象并返回一个迭代器对象,它交替迭代两个接收到的迭代器对象的项目。 zip函数应该在较短的迭代器对象的最后一项之后停止使用通配符,以便可以将zip函数应用于不同类型的迭代器对象。

为此,我首先创建了IteratorUtils类。请注意,zip功能的设计也不是一成不变的。在任务中它只说:“zip方法接收两个迭代器对象并返回一个迭代器对象,它交替迭代两个接收到的迭代器对象的项目。”

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

然后我创建了类ZipIterator。在阅读完答案和一些教程后,我了解了此任务中有界类型参数的含义。像user1803551所说的,ZipIterator类不应该是通用的。我只需要意识到我找到了普通的超类(这里是对象)。因此,我不得不对我ZipIterator类更改为以下几点:

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 
+0

好!关于你的解决方案的一件事是:不要把'Iterator'字段作为原始类型 - 使它们也是通用的。关于你的问题的一件事是:你在这里的答案中增加了明确的规则,但如果你将它们添加到问题中以避免混淆,它会有所帮助。最佳做法是完全引用分配。 – user1803551

相关问题