如果Fruit
类是superClass而Apple
和Orange
是Fruit的子类,
GoldenDelicious
和Macintosh
是Apple
的子类。
假设给出以下声明:
Fruit fruit = new GoldenDelicious();
Orange orange = new Orange();
用解释
回答这个问题假设方法makeAppleCider
在Apple
类中定义。能够
fruit
调用此方法?橙色可以调用这个方法???
我的回答是:可以 水果调用这个方法?没有因为没有明确的演员,必须做明确演员 fruit实例,用于调用Apple类中定义的方法。剂量这个答案是真的????
答案 0 :(得分:1)
这将深入研究变量的静态和动态类型。
Fruit fruit;
此行声明了一个变量fruit
,其静态类型为Fruit
。这种类型永远不会改变(毕竟它是静态的)并且是你通常会使用的类型。
fruit = new GoldenDelicious();
此行是为该变量指定值为GoldenDelicious
的行。变量的动态类型确实会发生变化以反映此更改。毕竟,变量实际上现在包含GoldenDelicious
。动态类型是你通常不会使用的东西,但它是你使用(邪恶)instanceof
时使用的(它确保在正确的位置调用覆盖函数)。
现在,您要这样做:
fruit.makeAppleCider();
这不起作用。结果,我们基本上只知道静态类型,而静态类型Fruit
对该方法一无所知。 (但是,在幕后,如果GoldenDelicious
和Macintosh
以不同方式实现该功能,动态类型将确保调用正确的版本。)
正如您在回答中提到的,显式强制转换可用于更改您正在使用的静态类型,因此您可以使其以这种方式工作。不过,最好不要这样做,因为应该避免演员阵容而不是“适当的OOP”。
总之,是的,你的回答是正确的。
(是的,我的描述有点技术性。我希望你能原谅我......)
答案 1 :(得分:0)
Fruit
没有makeAppleCider
方法的“知识”。 makeAppleCider
在子类中定义,不是Fruit
的成员。类只能访问它或其父项之一定义的方法。给定某个类的类,您必须跟踪类层次结构以查看可以访问的方法。您可以将变量的类型视为步骤备份类层次结构的起始位置。
如果您希望所有类都有访问权限的方法,请将其放在层次结构的根目录中。显然,使用该方法的逻辑应该是有意义的,否则使用您的代码的人会感到困惑。
答案 2 :(得分:0)
另一个选择当然是使用“接口” - 一种穷人的多重继承(但比完全多重继承更容易理解和实现)。
你可以,例如,有一个类似的界面(没有语法检查):
public interface CiderFruit {
public void makeCider();
}
然后Apple可以实现界面:
public class Apple extends Fruit implements CiderFruit {
....
public void makeCider() {
doStuff();
}
....
}
如果您有一个Quince类,它可以实现相同的界面,可以使用Apple或Quince,将其转换为CiderFruit(如果不确定它是Apple还是Quince),并调用makeCider()
。 (也可以直接使用输入为Apple或Quince的引用来调用。)