0

我有以下代码。为什么这行得通?铸造是必要的吗?

static public Food createMeal(Food f)
      throws Exception
  {

    if (f instanceof Bread)
    {
      return (Bread) f;
    }
    else if (f instanceof Meat)
    {
      return (Meat) f;
    }
    else if (f instanceof Milk)
    {
      return (Milk) f;
    }

    throw new Exception("NotAFood!");
  }
4

5 回答 5

4

不,向下转换是不必要的,实际上是无操作:

  1. 检查instanceof确保向下转换不会失败;
  2. 每个向下转换的引用都会立即Foodreturn语句向上转换回。

该函数可以更紧凑地编写,如下所示:

  static public Food createMeal(Food f) throws Exception {
    if ((f instanceof Bread) || (f instanceof Meat) || (f instanceof Milk)) {
      return f;
    } else {
      throw new Exception("NotAFood!");
    }
  }

话虽如此,instanceof在条件语句中的使用通常是糟糕设计的标志。想象一下添加一个新的Food. 现在您必须重新访问instanceof以这种方式使用的代码中的每一个地方,并适当地修改它。

更好的设计是在基类中定义一个合适的虚函数,并在派生类中覆盖它。

于 2012-05-18T14:44:11.460 回答
3

您不需要else在这里,因为如果满足先前的条件,那么return将简单地转义整个方法:

if (f instanceof Bread)
{
  return (Bread) f;
}
if (f instanceof Meat)
{
  return (Meat) f;
}
if (f instanceof Milk)
{
  return (Milk) f;
}

throw new Exception("NotAFood!");

不,这里不需要向下转换。实际上,您可以编写这样的等效函数:

static public Food createMeal(Food f) throws Exception {
    if(f instanceof Bread || f instanceof Meat || f instanceof Milk) {
        return f;
    }
    throw new Exception("NotAFood!");
}
于 2012-05-18T14:45:03.427 回答
1

因此,如果编译,则意味着 Milk、Bread 和 Meat 是 Food 的子类(它们“扩展”了 Food)。我假设是这种情况。如果是这样,那么这就是编译的原因。

现在,这意味着牛奶、面包和肉类可以被视为食物,但在内部它们是不同的(即一个是面包,一个是牛奶,一个是肉类,每个都有自己独特的成员变量在食物之上物品)

在 Java 中,变量 f 接受任何 Food 和 Food 的任何子类。但是,您传递的任何食物(包括肉类、牛奶和面包)都将被视为 Food 对象,而忽略它们是特定种类的 Food。

如果你想准确地找到它们是什么类型的 Food 子类,你可以使用 instanceof 操作符找出并采取行动。然后,您会将它们转换为它们的实际特定类型,以从这些对象调用特定方法。

您的代码:您正在做的只是返回一个实际的食物项目,因此不需要强制转换。默认情况下,Java 将牛奶、面包和肉类视为食物,默认情况下它们可以代替食物项返回。另一方面,如果您想访问 Meat、Bread 或 Milk 对象的特定属性,那么您将需要强制转换。您需要告诉 java 这些 f 不仅仅是食物,而是肉类、面包或牛奶。例如,如果您的 Milk 类有一个 getFatPercent() 方法,那么您需要执行 ((Milk)f).getFatPercent()

假设可以有更多 Food 的子类,您的代码相当于:

static public Food createMeal(Food f) throws Exception {
    if(f instanceof Milk || f instanceof Meat || f instanceof Bread)
        return f;
    else
        throw new Exception("Not a valid Food");
}
于 2012-05-18T14:59:40.813 回答
0

不需要铸造。不,你不需要一个 else if 之后的 else。事实上 else 总是可选的

于 2012-05-18T14:44:50.807 回答
-1

请注意,该else语句并不总是可选的。比如下面的代码没有编译,因为没有else语句!编译器感到困惑,因为 check() 方法必须返回 aboolean并且认为存在ifandelse-if语句都无法执行的情况,因此 check() 永远不会返回 a boolean

static boolean check(int x) {
    if (x < 5) {
        return true;
    } else if (x >= 5) {
        return false;
    }
}

public static void main(String[] args) {
    check(5);
}
于 2019-03-29T07:53:46.093 回答