有没有可能在超类对象上调用子类的方法?

动物是狗和狗的超级有一种叫做树皮的方法

public void bark() { System.out.println("woof"); } 

考虑以下几点:

 Animal a = new Dog(); if (a instanceof Dog){ a.bark(); } 

会发生什么?

  1. 该分配是不允许的
  2. 树皮的呼叫是允许的,并在运行时打印“woof”
  3. 树皮的呼叫是允许的,但没有打印
  4. 对树皮的调用导致编译时错误
  5. 对树皮的调用导致运行时错误

我说2,因为我们正在检查对象是否是狗; 因为狗是与树皮方法类,如果它是,那么我们把它打印出来:s

我的理解在这里正确吗?

这不会被编译,因为动物没有叫做树皮的方法。 想想这样,所有的狗都是动物,但不是所有的动物都是狗。 所有的狗叫,但不是所有的动物树皮。

不 – 答案是;

4)对树皮的调用会导致编译时错误

树皮方法并没有被定义为指定types的动物的方法,因此会导致编译时间问题; 这可以通过铸造解决;

 ((Dog)a).bark(); 

关键在于以下行:

 Animal a = new Dog(); 

尽pipe创build了一个Dog的新实例,但是它的引用是由a被声明为Animaltypes的实例引用的。 因此,任何提及a使得new Dog被当作Animal来处理。

因此,除非Animal有一个bark方法,否则下面这行会导致编译器错误:

 a.bark(); 

即使a被testing以查看它是否为Dog a instanceof Dog ,并且Dog a instanceof Dog实际上会返回true ,但variablesa仍然是Animaltypes的,所以if语句中的块仍然将a作为Animal处理。

这是静态types语言的一个特性,其中variables被提前分配一个types,并且在编译时检查这些types是否匹配。 如果这个代码是在dynamictypes语言上执行的,那么在运行时检查这些types,就可以允许类似下面的内容:

 var a = new Dog(); if (a instanceof Dog) a.bark(); 

a.bark()只保证在实例是Dog时候执行,所以对bark的调用将始终有效。 但是,Java是一种静态types的语言,所以这种types的代码是不允许的。

这是4.你不能问一个通用的动物 – 这是你的代码说的是 – 吠叫。 因为你可以轻而易举地说

 Animal a = new Cat(); 

树皮线没有办法知道你没有。

如果想法是从超类对象打印子类方法,这将工作:

而不是Animal a = new Dog(); if (a instanceof Dog){ a.bark(); } Animal a = new Dog(); if (a instanceof Dog){ a.bark(); } Animal a = new Dog(); if (a instanceof Dog){ a.bark(); }改为

 Animal a = new Dog(); if (a instanceof Dog){ Dog d = (Dog) a; d.bark(); } 

这将超类转换回子类并打印它。 虽然它的devise不好,但它的一种方法就是知道哪个子类对象dynamic地指向它。

在Head First Java中,他们使用电视遥控器的非常好的类比作为参考 ,将电视作为参考指向的对象 。 如果您的遥控器只有button(方法)可以打开,closures,上下和上下调整音量,那么无论您的电视有什么酷炫function都无所谓。 你仍然只能从你的遥控器做这几件基本的事情。 例如,如果您的遥控器没有静音button,则无法将电视静音。

动物参考只知道动物的方法。 无关紧要的对象有什么其他的方法,你不能从一个Animal引用访问它们。

仅供参考,这不是一个好的devise。

几乎任何时候你有这种forms的代码:

 if (x instanceof SomeClass) { x.SomeMethod(); } 

你滥用types系统。 这不是使用类的方式,也不是编写可维护的面向对象代码的方法。 这是脆弱的。 这是错综复杂的。 这不好。

您可以在基类中创build模板方法,但必须调用基类中存在的方法,并在子类中重写。

在Java(只有我知道的语言),你可以创build一个空方法,并在超级类中调用它。 然后你可以在子类中重写它来做任何你想要的。 这样超类调用它的子类的方法。

 public class Test { public static void main(String[] args){ Snake S = new Snake(); Dog d = new Dog(); } } class Animal{ //Super Class public Animal(){ bark(); //calls bark when a new animal is created } public void bark(){ System.out.println("this animal can't bark"); } } class Dog extends Animal{ //Subclass 1 @Override public void bark(){ System.out.println("Woof"); } } class Snake extends Animal{//Subclass 2 public void tss(){ } } 

此代码调用Snake的对象,然后调用Dog的对象。 它将这写到控制台:

 this animal can't bark Woof 

Snake没有任何树皮方法,所以叫超类“方法。 它将第一行写入控制台。 狗有一个树皮方法,所以超类叫它。 它将第二行写入控制台。

“我说我们正在检查对象是否是一只狗;因为狗是带有树皮方法的类,如果是的话,我们会打电话给它打印出来:

你的理由是正确的,但这不是它的工作方式。

Java是一种静态types语言,意味着对象可以响应的方法的有效性在编译时被validation。

你可能会认为这个支票:

 if( a instanceof Dog ) 

会做,但实际上没有。 编译器所做的是检查声明types的“接口”(在这种情况下为Animal)。 “接口”由Animal类声明的方法组成。

如果在超类Animal中未定义bark()方法,编译器会说:“嘿,那不行”。

这是有帮助的,因为“有时候”我们在编码时犯了拼写错误(例如,inputbarck())

如果编译器没有提醒我们这个问题,那么你就不得不在“运行时”find它,而不是一直用清晰的消息(例如IE中的javascript表示类似“意外对象”的东西)

尽pipe如此,Java这样的静态types语言允许我们强制调用。 在这种情况下,它使用“cast”运算符()

喜欢这个

 1. Animal a = new Dog(); 2. if (a instanceof Dog){ 3. Dog imADog = ( Dog ) a; 4. imADog.bark(); 5. } 

在第3行中,您正在“铸造”为Dogtypes,因此编译器可能会检查树皮是否是有效的消息。

这是对编译器的说明:“嘿,我是程序员,我知道我在做什么”。 而编译器,检查,Ok,dog,可以收到消息bark(),继续。 然而,如果在运行时动物不是狗,运行时exception将会boost。

演员阵容也可以缩写为:

 if( a instanceof Dog ) { ((Dog)a).bark(); } 

这将运行。

所以,正确答案是4:树皮的调用导致编译时错误

我希望这有帮助。