class Movie {
public void play() {
System.out.println("playing movie");
}
}
class DVD extends Movie {
@Override
public void play() {
System.out.println("playing dvd");
}
public void menu() {
System.out.println("showing menu");
}
}
public class Main {
public static void main(String[] args) {
Movie m = new DVD();
m.play();
m.menu(); //error
}
}
据我了解,m是DVD对象。 因此,它会打印出“正在播放DVD”。 但是为什么
m.menu()
如果未从父类Movie覆盖它,给我一个错误吗? 抱怨我在Movie类中没有menu()方法。
此外,在这种情况下,您将某些对象声明为
Parent obj = new children();
像这样吗? 当您要确保子类中的方法是 被父母取代? 如果是这种情况,为什么不直接在父类中创建方法 “抽象”甚至使父作为接口? 我的标题可能会引起误解,但是这种行为被称为“向上投射”吗?或多态?j
答案 0 :(得分:3)
当您看到Movie m = new DVD()
时,您即人知道m
是DVD。但是编译器并不知道-它只知道这是电影,因为这就是您告诉它的一切。因此,当看到m.menu()
时,它将在Movie上寻找该方法,但找不到。它不会分析您的代码来确定m
实际上是Menu的子类,尤其是DVD的子类,并且该确实具有menu()
。它只考虑Movie m
,因此抱怨Movie没有方法menu()
。
在Java中,这种情况一直发生,您可能会遇到类似这样的行:
List<Foo> myList = new ArrayList<>();
请参阅"What does it mean to 'program to an interface'?"关于为什么要这样做的信息。但对于您的问题,请特别注意ArrayList定义了List中未定义的方法trimToSize()
。如果您如上所述声明myList
,则将无法调用myList.trimToSize()
。
答案 1 :(得分:1)
我希望这会有所帮助:
就像人们评论的那样,产生错误的原因是因为m被(您)定义为电影。实际上,作为DVD(也是电影)并不矛盾,因此可以正常工作。
将子对象当作父对象存储的原因有很多,例如,如果您希望对属于一个父类的不同子对象(例如DVD,BluRay,盒式磁带等)进行统一处理
您可能还希望Movie本身具有功能,因此将其抽象化对您没有用(想象您正在设计游戏,并且想说Orc和Uruk-Hai,它们是兽人,您仍然希望两者都能独立发挥作用。
最后,不确定这是否是您感兴趣的内容,通过查找“访客模式”,它可能与您最后要问的内容有关。
答案 2 :(得分:1)
电影m =新DVD();
由于运行时多态性,
在运行时保留子实例,但是Java是静态/结构类型编程,因此它始终严格维护其类型,因此 Movie 对象始终会找到其结构属性。因此,电影对象 m 在运行时找不到 menu()方法。因此,如果要实现此目标,则必须执行以下操作
DVD m =新DVD();
或
对象m =新DVD();
(((DVD)m).menu();
或
电影m =新DVD();
DVD d =(DVD)m; m.menu();
但是,如果Java是动态类型编程(其中Duck类型用于在运行时解析对象结构),您的想法是正确的。
有关type的更多详细信息,请阅读here