2016-08-13 97 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

相關問題