【问题标题】:More advanced usage of interfaces更高级的接口使用
【发布时间】:2011-02-06 20:49:48
【问题描述】:

说实话,我不太确定我自己是否理解这个任务 :) 我被告知要创建类 MySimpleIt,它实现了 Iterator 和 Iterable,并允许运行提供的测试代码。对象的参数和变量不能是集合或数组。
代码:

 MySimpleIt msi=new MySimple(10,100,
                           MySimpleIt.PRIME_NUMBERS);

 for(int el: msi)
   System.out.print(el+" ");    
 System.out.println();

 msi.setType(MySimpleIterator.ODD_NUMBERS);
 msi.setLimits(15,30);
 for(int el: msi)
   System.out.print(el+" ");    
 System.out.println();

 msi.setType(MySimpleIterator.EVEN_NUMBERS);
 for(int el: msi)
   System.out.print(el+" ");    
 System.out.println();

我应该得到的结果:

11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 


15 17 19 21 23 25 27 29 


16 18 20 22 24 26 28 30

这是我的代码:

import java.util.Iterator; 
interface MySimpleIterator{
    static int ODD_NUMBERS=0;
    static int EVEN_NUMBERS = 1;
    static int PRIME_NUMBERS = 2;

    int setType(int i);
}

public class MySimpleIt implements Iterable, Iterator, MySimpleIterator {    
    public MySimple my;

    public MySimpleIt(MySimple m){ 
        my = m;      
    }

    public int setType(int i){
        my.numbers = i;
        return my.numbers;
    }

    public void setLimits(int d, int u){
        my.down = d;
        my.up = u;
    }

    public Iterator iterator(){
        Iterator it = this.iterator();
        return it;
    }

    public void remove(){  
    }

    public Object next(){
        Object o = new Object();
        return o;
    }

    public boolean hasNext(){
        return true;
    }

}

class MySimple {
    public int down;
    public int up;
    public int numbers;

    public MySimple(int d, int u, int n){
        down = d;
        up = u;
        numbers = n;
    }
}

在测试代码中,创建 MySimpleIt msi 对象时出现错误,因为它找到的是 MySimple 而不是 MySimpleIt。我在 for-each 循环中也有错误,因为编译器想要“ints”而不是 Object。有人知道如何解决吗?

【问题讨论】:

  • 你不应该使用 new MySimpleIt() 而不是 new MySimple() 吗?
  • 看起来测试代码使用了 3 个不同的名称来表示应该是同一个类:MySimple、MySimpleIt 和 MySimpleIterator。
  • 这是一个不寻常的请求,因为 SimpleIt 是它自己的迭代器。因此,您的 iterator() 方法应该返回“this”。这应该可以帮助您入门,我建议您深入研究几个标准迭代器和可迭代对象,看看它们是如何工作的,一旦您了解了模式,剩下的就是在 next() 方法中填充逻辑,以便为您提供正确的数字(我很确定你可以从 Java 数学库中得到质数,这应该会让事情变得非常简单)
  • 不要创建一个既是 Iterable 又是它自己的 Iterator 的对象。
  • @Thilo 他被特别要求这样做。

标签: java interface iterator iteration


【解决方案1】:

这个作业的设计有很多错误。

使用enum

测试代码包含这个sn-ps:

MySimpleIt(erator?).PRIME_NUMBERS
MySimpleIt(erator?).ODD_NUMBERS
MySimpleIt(erator?).EVEN_NUMBERS

在一个地方类型是MySimpleIt,在另一个地方它是MySimpleIterator。无论哪种方式,名称都建议使用接口来定义一堆常量。这不是 interface 的正确使用!!!

改用enum 会更好:

enum SequenceType {
  PRIME_NUMBERS, ODD_NUMBERS, EVEN_NUMBERS;
}

参见:Effective Java 2nd Edition 第 30 条:使用枚举代替 int 常量。


考虑interface 的多个实现,而不是setType 的单体应用

看起来您的音序器应该能够随心所欲地切换音序类型。这将导致该类成为一个巨大的 blob,它必须知道如何生成每种类型的序列。它可能只适用于这里给出的 3 种类型,但如果您以后想要添加更多类型的序列,这绝对是一个糟糕的设计。

考虑为不同类型的序列对同一接口进行不同的实现。您可能想要定义一个 AbstractIntegerSequencer 来定义基本功能(重置边界、回答 hasNext()iterator() 等),将子类委托给 abstract protected int generateNext()@Override。这样,要生成的序列类型的细节很好地封装到每个子类中。

您仍然可以保留enum SequenceType 用于实例化这些不同子类的static 工厂方法,每个序列类型一个,但这些序列本身可能不能随心所欲地切换类型。


使用泛型

您的类型不应设为implements Iterator,而应设为implements Iterator<Integer>

来自JLS 4.8 Raw Types(强调他们的):

仅允许使用原始类型作为对遗留代码兼容性的让步。强烈反对在将泛型引入 Java 编程语言之后编写的代码中使用原始类型。 Java 编程语言的未来版本可能会禁止使用原始类型

另请参阅Effective Java 2nd Edition 第 32 条:不要在新代码中使用原始类型。


不要将Iterator<T>Iterable<T> 混淆。

假设你有这样的东西:

IntegerSequencer seq = new PrimeSequencer(0, 10);

for (int i : seq) {
  System.out.println(i);
} // prints "2", "3", "5", 7"

for (int i : seq) {
  System.out.println(i);
} // what should it print???

如果您将seq implements Iterable<Integer>, Iterator<Integer>@Override Iterator<Integer> iterator() 设置为return this;,那么第二个循环将不会打印任何内容,因为seq 是它自己的iterator(),此时没有更多hasNext()对于seq

Iterable<Integer> 的正确实现应该能够为用户生成尽可能多的独立Iterator<Integer>,并且这样的实现将再次打印上述代码中010 之间的素数。


stackoverflow 的进一步阅读

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多