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

Java 如何向类添加方法并在其超类的for样式循环中使用它们?,java,oop,generics,Java,Oop,Generics,假设我有这样一个通用数组: ArrayList<Fruit> fruits = new ArrayList<Fruit>(); interface FruitVisitor { void visit(Banana banana); void visit(Apple apple); } 如果水果是香蕉,我想看看它有多圆,所以 for (Fruit f : fruits) { if (f instanceof Bannana) f

假设我有这样一个通用数组:

ArrayList<Fruit>  fruits = new ArrayList<Fruit>();
interface FruitVisitor {
    void visit(Banana banana);
    void visit(Apple apple);
}
如果水果是香蕉,我想看看它有多圆,所以

for (Fruit f : fruits) {
    if (f instanceof Bannana)
        f.checkHowRoundBannanaIs();
}
我必须将
checkhowrandbannnais()
方法放在水果类中,即使水果可能不是香蕉,因为如果f不在水果类中,我就不能在f上使用该函数,否则会出现未定义的方法错误(或类似错误)


对于一个或两个方法来说,这很好,但过了一段时间,它会使类变得笨重和丑陋。因此,我的问题是,如何向类添加方法并在其超类的for样式循环中使用它们?

最类似于您尝试将
f
转换为
香蕉的技术:

if(f instanceof Bannana)
    ((Banana)f).checkHowRoundBannanaIs()
我不确定这是否真的是你想要的

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

简单的回答,你真的不能

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

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

不过,
实例和向下投射通常都被认为是不好的做法。为了避免这种情况,您可以实现。以下是您需要采取的步骤:

  • 创建一个如下所示的访问者界面:

    ArrayList<Fruit>  fruits = new ArrayList<Fruit>();
    
    interface FruitVisitor {
        void visit(Banana banana);
        void visit(Apple apple);
    }
    
  • 让所有水果接受访客:

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

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

  • 您不必将
    checkHowRoundBanannaIs()
    放入
    Fruit
    类中。一旦您知道
    f
    Banana
    的一个实例,您就可以安全地将
    f
    强制转换为类型
    Banana
    。现在您有了一个
    Banana
    实例,可以调用任何
    Banana
    特定方法(包括
    checkhowrandbananais()


    既然你已经在检查它是否是香蕉,你可以把它扔给香蕉,然后再做检查

    for(fruit f : fruits)
    {
        if(f instanceof Banana) {
            Banana b = (Banana)f;
            b.checkHowRoundBananaIs()
        }
    }
    
    …从逻辑上讲,这不是“它的超级类的for样式循环”

    如果您要导入Bannana的实例,则必须导入Bannana的实例(虽然我想您应该改为键入Banana)。导入后,没有理由不将
    f
    强制转换为
    Banana
    。这样做可以访问
    Banana
    的所有方法

    简言之,除非您确实想将
    obj1
    用作
    XXX
    ,否则通常不会执行XXX的
    obj1实例检查


    当然还有更好的方式,比如访问者模式(参见其他帖子)或者将函数提取到超类。虽然我想你已经接受了设计上的一些问题,但你不想解决它。

    这些示例是用Java编写的,但这不是Java的问题。对。这个问题对于使用单一分派机制的所有语言来说都是常见的。
    for(fruit f : fruits)
    {
      if(f instanceof Bannana)
          f.checkHowRoundBannanaIs()
    }