如何向类添加方法并在其超类的for-style循环中使用它们?

时间:2011-10-12 20:01:00

标签: java oop generics

说我有这样的通用数组:

ArrayList<Fruit>  fruits = new ArrayList<Fruit>();

然后我添加了许多不同的水果,这些水果都延伸了类水果,并循环通过它们

for (Fruit f : fruits) {

}

如果水果是香蕉,我想检查它是多么圆,所以......

for (Fruit f : fruits) {
    if (f instanceof Bannana)
        f.checkHowRoundBannanaIs();
}

我必须将checkHowRoundBannnaIs()方法放在水果类中,即使水果可能不是香蕉,因为如果它不在水果类中,我就不能使用f上的函数,否则我得到一个未定义的方法错误(或类似的东西)。

对于一种或两种方法来说这很好,但过了一段时间它会让这个类变得笨重而且难看。所以我的问题是,我如何向类中添加方法并在超类的for-style循环中使用它们?

5 个答案:

答案 0 :(得分:3)

  

所以我的问题是,如何向类中添加方法并在超类的for-style循环中使用它们?

简短回答,你不能真的。

如果你想调用for循环体中的方法,instanceof和向下转换是我能想到的唯一方法:

for (Fruit f : fruits) {
    if (f instanceof Banana)
        ((Banana) f).checkHowRoundBananaIs();
    // ...
}

instanceof和向下投射通常被认为是不好的做法。为避免这种情况,您可以实施visitor pattern。以下是您需要采取的步骤:

  1. 创建一个这样的访问者界面:

    interface FruitVisitor {
        void visit(Banana banana);
        void visit(Apple apple);
    }
    
  2. 让所有水果接受访客:

    abstract class Fruit {
        // ...
        public abstract void accept(FruitVisitor fv);
    }
    
    class Banana extends Fruit {
        public void accept(FruitVisitor fv) {
            fv.visit(this);
        }
    
        public void checkHowRoundBananaIs() { ... }
    }
    
  3. 创建一个访问者,为每种类型的水果采取适当的操作,并将其作为参数传递给列表中每个水果的accept方法:

    FruitVisitor fv = new FruitVisitor() {
        public void visit(Banana banana) {
            banana.checkHowRoundBananaIs();
        }
    
        public void visit(Apple apple) {
            // ...
        }
    };
    
    for (Fruit f : fruits)
        f.accept(fv);
    

答案 1 :(得分:2)

与您尝试过的方法最相似的技巧是将f转换为Banana

if(f instanceof Bannana)
    ((Banana)f).checkHowRoundBannanaIs()

我不确定这是否真的是你想要的。

答案 2 :(得分:1)

您不必将checkHowRoundBanannaIs()放入Fruit课程。一旦您知道fBanana的实例,就可以安全地将f向下转换为类型Banana。现在您已拥有Banana个实例,您可以调用任何Banana特定方法(包括checkHowRoundBananaIs()

for(final Fruit f : fruits)
{
    if(f instanceof Banana)
    {
        final Banana b = (Banana) f;
        b.checkHowRoundBananaIs();
    }
}

答案 3 :(得分:1)

看到你已经在检查它是否是香蕉,你可以将它投入香蕉然后进行检查..

for(fruit f : fruits)
{
    if(f instanceof Banana) {
        Banana b = (Banana)f;
        b.checkHowRoundBananaIs()
    }
}

答案 4 :(得分:0)

for(fruit f : fruits)
{
  if(f instanceof Bannana)
      f.checkHowRoundBannanaIs()
}

...这不是“超级类的for-style循环”。从逻辑上讲。

ASA你做instanceof Bannana你必须导入Bannana(虽然我想你想要输入Banana)。导入后,没有理由不将f投射到Banana。一旦你这样做,你就可以访问Banana的所有方法。

简而言之,通常您不会进行obj1 instanceof XXX检查,除非您确实要将obj1用作XXX

当然,有更好的方式,如访问者模式(请参阅其他帖子)或将功能提取到超类。虽然我猜你已经接受了你的设计有些问题而且你不想修复它。