在JAVA中使用一个抽象方法的重载方法

时间:2017-02-01 05:32:57

标签: java inheritance abstract-class abstract

给出一个抽象类

public abstract class AbstractStomach {
    public abstract void consume(Food food);
}

我想要一些具有不同重载方法的具体类:

public class FruitStomach extends AbstractStomach {
    public static class Apple extends Food {}
    public static class Orange extends Food {}
    @Override
    public void consume(Apple food) {...}
    @Override
    public void consume(Orange food) {...}
}

public class MeatStomach extends AbstractStomach {
    public static class Beef extends Food {}
    @Override
    public void consume(Beef food) {...}
}

上面的工作并没有成功,因为它迫使我在每个具体的类中实现通用的consume(Food)抽象方法。

但是我不希望具体的类实现consume(Food),因为它们已经由它们的重载变体来处理,实际上,每个具体的类应该只使用不同的特定食物,而不是任何食物,所以

AbstractStomach stomach = new FruitStomach();
stomach.consume(new Beef());

应该给出错误。

如果我在抽象类中删除抽象方法,那么就没有必要让它们扩展抽象类,因为它没有为它们提供实现的指导。

如何修复上述设计,以便每个具体类都可以使用重载方法,但他们知道有一个抽象方法consume()可以实现,但不需要实现consume(Food)

修改

我可以在不使用重载的情况下解决上述问题,例如

public class FruitStomach extends AbstractStomach {
    public static class Apple extends Food {}
    public static class Orange extends Food {}
    @Override
    public void consume(Food food) {
        if (food instanceof Apple) {
           ...
        } else if (food instanceof Orange) {
           ...
        } else {
           // throws an error
        }
    }
}

但这不是我想要的。我想看一个使用方法重载的解决方案。

5 个答案:

答案 0 :(得分:4)

抽象类中的抽象方法不仅仅是提供指导实现的方法"。抽象类允许您拥有可以是抽象类的任何子类的对象。也就是说,您可以使用

之类的方法
public void evaluateDigestion(AbstractStomach stomach) {
}

您可以使用任何类型的Stomach对象,FruitStomachMeatStomachDessertStomach或其他任何内容来调用它。在evaluateDigestion内,该方法可以调用stomach.consume(someKindOfFood)。由于这是为抽象类定义的consume(在编译时evaluateDigestion不知道类是什么),因此consume使用Food参数。然后,在运行时,对consume的呼叫将"发送"到为具体类定义的consume(Food food)方法。这就是为什么必须为每个具体类定义具有consume参数的Food的原因。调度调用不会使用AppleOrange等参数搜索重载方法; Java不会这样做。 (所以你声明它已经被重载变种"处理了,这是不正确的;重载和覆盖之间存在很大的差别,这可能会让新手感到困惑。)

所以你必须写

public void consume(Food food)

在每个具体课程中。实现这一目标的非常笨重的方式是

public void consume(Food food) {
    if (food instanceof Apple) {
        consume((Apple)food);  // calls the overloaded version because you've use a cast to tell Java how to view the object
    } else if (food instanceof Orange) {
        consume((Orange)food);
    } else {
        throw ... // some exception that occurs when you try to eat the wrong kind of food
    }
}

最好在Food中定义一个抽象方法,假设Food是抽象的:

public abstract class Food {
    public void abstract consumedBy(AbstractStomach stomach);
}

AppleOrange等类中定义具体版本,然后编写consume之类的

public static void consume(Food food) {
    food.consumedBy(this);
}

但是,这不会阻止尝试让FruitStomach消费牛肉。您可能必须使用instanceof来确保食物兼容。 (一种可能性:定义扩展Fruit的类Food,并创建Apple的{​​{1}}和Orange子类;然后您可以说Fruit要确认它是正确的食物。可能有比这更好的设计模式。我不能想到一个随便的。)

答案 1 :(得分:3)

您可以使用泛型来(部分)解决您的问题:

AbstractStomach定义了一个类型参数T,它声明了它消耗的Food类型:

public abstract class AbstractStomach<T extends Food> {
    public abstract void consume(T food);
}

然后,您可以声明食物类型Fruit和相应的FruitStomach

public class Fruit extends Food {}
public class FruitStomach extends AbstractStomach<Fruit> {
    public static class Apple extends Fruit {}
    public static class Orange extends Fruit {}
    @Override
    public void consume(Fruit food) {}
}

以及类似的课程MeatMeatStomach

public class Meat extends Food {}
public class MeatStomach extends AbstractStomach<Meat> {
    public static class Beef extends Meat {}
    @Override
    public void consume(Meat food) {}
}

答案 2 :(得分:1)

要@Override方法,您需要具有相同的返回条件或子类型,名称和参数,以便您无法更改&#34;食品食品&#34;在&#34;橘子橙&#34;。

我认为你可以做的是对你需要在具体类中的方法内工作的对象(或者你使用instanceof)进行转换。或者更好的是你可以创建一个对象:

Food orange = new Orange();
Food apple = new Apple(); 

因此使用Orange类中的第一次方法覆盖,第二次使用Apple类中的一个方法。

如果它不是您想要的解决方案,请发表评论,以便我可以尝试别的。

答案 3 :(得分:1)

The above doesn't work as it is forcing me to implement also the generic consume(Food)

这是正确行为。通过抽象类AbstractStomach中的合同,您同意,

  

任何扩展AbstractStomach的内容都有一个方法   consume(Food)任何食物),然后在子类中   强迫它只有两种类型的食物,从而绕过合同。

答案 4 :(得分:1)

您遇到的问题是您的抽象方法签名需要将名为 Food 的超类传递给consume-method。

这个抽象类的每个实现(以及它的抽象方法)都必须覆盖相同的签名。

e.g。

   public FruitStomach extends AbstractStomach {
    public static class Apple extends Food {}
    public static class Orange extends Food {}
    @Override
    public void consume(Food food) {
      if (food instanceof Orange) {
        Orange orange = (Orange) food;
        // do smth. with orange     
      } else{
        // so smth with food
      }
    }

   public MeatStomach extends AbstractStomach {
      public static class Beef extends Food {}
      @Override
      public void consume(Food food) {
        Beef beef = (Beef) food;
        // do smth. with beef...
      }
    }

可行。虽然这不是非常干净的代码,但如果您的代码正确连接在一起,则无法进行编译时验证。 但正如你所说,如果你在错误的输入食物上调用错误的Stomach.consume() - 方法,你可能会引发一个ClassCastException,你可以处理它。