【问题标题】:Override iterator type覆盖迭代器类型
【发布时间】:2014-01-28 09:38:38
【问题描述】:

我有两个父类和它们的两个子类。我对迭代器方法的返回类型有问题,它总是父类类型,子类不能覆盖它。

请考虑以下代码:

public class Attribute {}

public class Attributes implements Iterable<Attribute> {
    protected ArrayList<Attribute> attrs = new ArrayList<Attribute>();

    public Iterator<Attribute> iterator() {
        return this.attrs.iterator();
    }
}

// -------

public class Attr extends Attribute {}

public class Attrs extends Attributes {}

// -------

for (Attr attr : attrs) {
    // Error! attrs.iterator() returns Attribute not Attr
}

for (Attribute attribute : attrs) {
    Attr attr = (Attr) attribute;
    // Works
}

是否可以覆盖迭代器返回类型?

【问题讨论】:

  • 基本上将 Collection 转换为 Collection 是行不通的,起初看起来不方便,但如果可以的话,您可以将 Child2 或 Parent 添加到 Collection当然是 runTimeException
  • 使用 (Attr) 属性对编译器说“我知道这可能会出错,我知道我在做什么并且我接受我的行为的后果”
  • 我知道强制转换是个坏主意,我正在寻找某种方式来覆盖 iterator() 并改变它的行为。
  • &lt;? extends Attribute&gt; 也不适用于 iterator() 因为 Iterator(接口)有 Iterator&lt;T&gt; iterator()

标签: java iterator


【解决方案1】:

被覆盖的方法必须与新方法兼容。

所以下面的覆盖是可以接受的:

public class Baa{
     .....
     public Baa returnSomething{
         return this;
     }
}


public class Foo extends Baa{
     .....
     @Override
     public Foo returnSomething{
         return this;
     }
}

即使您将对象视为 baa,一切仍然有效

public static void main(String[] args){
    Baa test=new Foo(); //a Foo is a Baa so no problem

    Baa getSomething=test.returnSomething(); //returns a Foo, but a foo can be used as as a baa so no problem

}

这不适用于泛型

如果集合发生同样的情况似乎很方便,但是您可以轻松创建一个会出现运行时错误的示例

Collection<Intger> numbers=new ArrayList<Intger>();
Collection<Number> falseNumbers=(Collection<Number>)numbers; //pretend not an error
falseNumbers.add(new Double()); ////eeeek!

逆变节省时间

使用泛型,如Returning a Collection from a method that specifies that it returns Collection 中所述,我们可以指示集合的最小和最大边界(基本上说它们只能包含可以转换为特定类型的对象。通过使用它,我们可以创建一个迭代器不需要强制转换:

public class Attribute {
    protected ArrayList<Attribute> attributes = new ArrayList<Attribute>();

    public Attribute(){
         //holding an array of yourself seems strange, but I am replicating the code in the question
         attributes.add(this);
    }

    public Iterator<? extends Attribute> iterator() {
        return this.attributes.iterator();
    }

    public static void main(String[] args){
        Attribute attribute=new Attribute();
        Iterator<? extends Attribute> it1=attribute.iterator();
        Attribute attributeInternat=it1.next();

        Attr attr=new Attr();
        Iterator<? extends Attr> it2=attr.iterator();
        Attr attrInternat=it2.next();
    }
}

public class Attr extends Attribute{
   protected ArrayList<Attr> attrs2 = new ArrayList<Attr>();
    public Attr(){
          //holding an array of yourself seems strange, but I am replicating the code in the question
          attrs2.add(this);
    }

    @Override
    public Iterator<? extends Attr> iterator() {
        return this.attrs2.iterator();
    }
}

这确保没有强制转换,并且所有内容都是完全类型安全的。

【讨论】:

  • 所以最好的方法是使用迭代器对象而不是foreach。谢谢理查德
  • @AHHP 是的,出于某种原因,foreach 似乎不喜欢这个,这本身就很有趣
猜你喜欢
  • 2014-06-08
  • 2023-03-23
  • 2020-07-08
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 2014-01-30
  • 2016-09-18
  • 1970-01-01
相关资源
最近更新 更多