是否可以在超类对象上调用子类的方法?
Posted
技术标签:
【中文标题】是否可以在超类对象上调用子类的方法?【英文标题】:Is it possible to call subclasses' methods on a superclass object? 【发布时间】:2010-10-28 06:54:04 【问题描述】:Animal 是 Dog 的超类 Dog 有一个叫 bark 的方法
public void bark()
System.out.println("woof");
考虑以下几点:
Animal a = new Dog();
if (a instanceof Dog)
a.bark();
会发生什么?
-
不允许分配
允许调用 bark 并在运行时打印“woof”
允许调用 bark,但不打印任何内容
对 bark 的调用导致编译时错误
对 bark 的调用导致运行时错误
我说的是 2,因为我们正在检查对象是否是狗;因为 dog 是其中包含 bark 方法的类,如果是,则我们调用它,它将打印出来:s
我的理解正确吗?
【问题讨论】:
建议将这里的问题改为“超类是否有其子类的方法?”或类似的。 诀窍是您正在检查以确保它是一只狗,但编译器没有建立 a.bark 仅在 a 是狗时才被调用的逻辑连接。为了调用 bark() 的目的,您必须明确告诉编译器将 a 视为 Dog,如下面的 Simon622 所述。 顺便说一句,这就是为什么许多人更喜欢“鸭式打字”的原因。例如,在 Python 中,等效代码甚至不需要检查a
是否为 Dog;只要a
在到达该行时有一个bark
方法,它就可以工作。
幸运的是只有 1 分,如果问题是“超类有其子类的方法吗?”我会得到标记的:@ 大声笑无论如何我可以在这里扩展问题,以便我可以检查更多
回复:鸭子打字--错误的答案。如果动物可以发出声音,makeNoise() 应该在动物基类中。您几乎不必使用强制转换。如果只有一些动物会发出噪音,那应该是 dog 扩展的子类(或者该方法应该抛出异常或返回 null)。好处是,如果你的类设计得当,你很少需要强制转换,所以如果你发现鸭式打字真的有用,请检查你的设计技巧。
【参考方案1】:
这不会编译,因为 Animal 没有名为 bark 的方法。这样想,所有的狗都是动物,但不是所有的动物都是狗。所有的狗都会吠叫,但并非所有的动物都会吠叫。
【讨论】:
【参考方案2】:否 - 答案是;
4) 对 bark 的调用导致编译时错误
bark 方法未定义为分配类型 Animal 上的方法,因此将导致编译时问题;这可以通过强制转换来解决;
((Dog)a).bark();
【讨论】:
【参考方案3】:它是 4。你不能要求一个通用的动物——这就是你的代码所说的 a ——吠叫。因为你可以很容易地说
Animal a = new Cat();
而树皮线没有办法知道你没有。
【讨论】:
【参考方案4】:关键在下面一行:
Animal a = new Dog();
虽然创建了Dog
的新实例,但它的引用是由a
声明的Animal
类型。因此,对a
的任何引用都会使new Dog
被视为Animal
。
因此,除非Animal
有bark
方法,否则以下行将导致编译器错误:
a.bark();
即使a
被测试以查看它是否是Dog
的一个实例,并且a instanceof Dog
将实际返回true
,变量a
仍然属于Animal
类型,所以if
语句中的块仍将 a
处理为 Animal
。
这是statically-typed languages 的一个功能,其中变量被提前分配了一个类型,并在编译时检查以查看类型是否匹配。如果此代码是在 dynamically-typed language 上执行的,在运行时检查类型,则可能允许执行以下操作:
var a = new Dog();
if (a instanceof Dog)
a.bark();
a.bark()
保证仅在实例为Dog
时执行,因此对bark
的调用将始终有效。但是,Java 是一种静态类型的语言,所以这种类型的代码是不允许的。
【讨论】:
+1 用于添加关于静态类型语言与动态类型语言的解释。 如果两个类都有 bark() 方法,会执行哪一个。 @Rahul Kadukar:如果“animal 是 dog 的超类”,并且两个类都有 bark() 方法,然后将 bark() 覆盖为子类 dog 中的 bark() 方法。因此,a.bark() 将执行 dog 类中的 bark() 方法。【参考方案5】:在Head First Java 中,他们将电视遥控器很好地类比为参考,而您的电视作为参考指向的对象。如果你的遥控器只有开、关、频道上下以及音量上下的按钮(方法),那么你的电视有什么很酷的功能并不重要。你仍然只能从遥控器上做那几件基本的事情。您无法将电视静音,例如,如果您的遥控器没有静音按钮。
Animal 参考只知道 Animal 方法。不管底层对象有什么其他方法,你都不能从 Animal 引用中访问它们。
【讨论】:
【参考方案6】:“我说 2,因为我们正在检查对象是否是狗;因为 dog 是其中包含 bark 方法的类,如果是,那么我们调用它,它将打印出:s”
您的理由是正确的,但事实并非如此。
Java 是一种静态类型语言,这意味着,对象可能响应的方法的有效性在编译时进行验证。
你可能会认为支票:
if( a instanceof Dog )
会,但实际上不会。编译器所做的是检查声明类型的“接口”(在这种情况下为 Animal )。 “接口”由 Animal 类上声明的方法组成。
如果 bark() 方法没有在超类 Animal 中定义,编译器会说:“嘿,这行不通”。
这很有帮助,因为“有时”我们在编码时会打错字(例如输入 barck())
如果编译器没有对此发出警告,您将不得不在“运行时”找到它,而且并不总是带有明确的消息(例如 IE 中的 javascript 会说“意外对象”之类的内容)
不过,像 java 这样的静态类型语言允许我们强制调用。在这种情况下,它使用“cast”运算符 ()
这样
1. Animal a = new Dog();
2. if (a instanceof Dog)
3. Dog imADog = ( Dog ) a;
4. imADog.bark();
5.
在第 3 行中,您正在“强制转换”为 Dog 类型,因此编译器可能会检查 bark 是否是有效消息。
这是对编译器的指令,说“嘿,我是这里的程序员,我知道我在做什么”。并且编译器检查,好的,狗,可以接收到消息 bark(),继续。然而,如果在运行时动物不是狗,则会引发运行时异常。
演员表也可以缩写为:
if( a instanceof Dog )
((Dog)a).bark();
这将运行。
所以,正确答案是4:“对 bark 的调用导致编译时错误”
我希望这会有所帮助。
【讨论】:
【参考方案7】:仅供参考,这不是一个好的设计。
几乎任何时候你都有这种形式的代码:
if (x instanceof SomeClass)
x.SomeMethod();
你在滥用类型系统。这不是使用类的方式,也不是编写可维护的面向对象代码的方式。它很脆。很复杂。这很糟糕。
您可以在基类中创建模板方法,但它们必须调用存在于基类中并在子类中被覆盖的方法。
【讨论】:
【参考方案8】:如果想法是从超类对象打印子类方法,这将起作用:
而不是Animal a = new Dog(); if (a instanceof Dog) a.bark();
改为
Animal a = new Dog();
if (a instanceof Dog)
Dog d = (Dog) a;
d.bark();
这会将超类转换回子类并打印它。 虽然它的设计很糟糕,但它是动态知道它指向哪个子类对象的一种方法。
【讨论】:
或者,如果你必须这样做,你可以这样做if(a instanceof Dog) ((Dog) a).bark();
【参考方案9】:
在 java(我只知道的语言)中,您可以创建一个空方法并在超类中调用它。然后你可以在子类中覆盖它来做任何你想做的事情。这样超类调用其子类的方法。
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 没有任何 bark 方法,因此调用了超类的方法。它将第一行写入控制台。 Dog 有一个 bark 方法,所以超类调用它。它将第二行写入控制台。
【讨论】:
以上是关于是否可以在超类对象上调用子类的方法?的主要内容,如果未能解决你的问题,请参考以下文章