动物是狗的超类 和狗有一种叫做树皮的方法
public void bark()
{
System.out.println("woof");
}
请考虑以下事项:
Animal a = new Dog();
if (a instanceof Dog){
a.bark();
}
会发生什么?
我说2,因为我们正在检查对象是否是狗;因为狗是带有树皮方法的类,如果是,那么我们称它为打印出来的:s
我的理解是否正确?
答案 0 :(得分:32)
由于Animal没有名为bark的方法,因此无法编译。想一想,所有的狗都是动物,但不是所有的动物都是狗。所有的狗都会吠叫,但不是所有的动物都会吠叫。
答案 1 :(得分:27)
不 - 答案是;
4)对bark的调用导致编译时错误
bark方法未定义为已分配类型Animal的方法,因此会导致编译时间问题;这可以通过铸造来解决;
((Dog)a).bark();
答案 2 :(得分:11)
密钥位于以下行:
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是一种静态类型的语言,因此不允许使用这种类型的代码。
答案 3 :(得分:5)
在Head First Java中,他们使用电视遥控器的非常好的类比来获取参考,将电视用作参考指向的对象。如果你的遥控器只有按钮(方法)可以打开,关闭,频道上下,以及音量增大和减小,那么电视的酷炫功能并不重要。您仍然只能从遥控器上执行这些基本操作。例如,如果遥控器没有静音按钮,则无法将电视静音。
动物参考只知道动物方法。底层对象的其他方法无关紧要,您无法从Animal引用中访问它们。
答案 4 :(得分:4)
它是4.你不能要求一个通用的动物 - 这是你的代码所说的 - 吠叫。因为你可以很容易地说
Animal a = new Cat();
并且树皮线没有办法知道你没有。
答案 5 :(得分:4)
如果想要从超类对象打印子类方法,这将起作用:
而不是Animal a = new Dog(); if (a instanceof Dog){ a.bark(); }
改为
Animal a = new Dog();
if (a instanceof Dog){
Dog d = (Dog) a;
d.bark();
}
这会将超类强制转换为子类并将其打印出来。 虽然它的设计很糟糕,但它是一种知道动态指向哪个子类对象的方法。
答案 6 :(得分:2)
仅供参考,这不是一个好的设计。
几乎任何时候你都有这种形式的代码:
if (x instanceof SomeClass)
{
x.SomeMethod();
}
你正在滥用类型系统。这不是使用类的方法,它不是编写可维护的面向对象代码的方法。它很脆弱。这是令人费解的。这很糟糕。
您可以在基类中创建模板方法,但是它们必须调用基类中存在的方法并在子类中重写。
答案 7 :(得分:2)
在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没有任何树皮方法,所以超级班级'方法被调用。它将第一行写入控制台。
狗有一种树皮方法,所以超类叫它。它将第二行写入控制台。
答案 8 :(得分:1)
“我说2,因为我们正在检查对象是否是狗;因为狗是带有树皮方法的类,如果是,那么我们称之为打印出来的:s”
你的理由是正确的,但这不是它的工作方式。
Java是一种静态类型语言,这意味着,在编译时验证对象可能响应的方法的有效性。
您可以考虑检查:
if( a instanceof Dog )
会这样做,但事实上并非如此。编译器所做的是检查声明类型的“接口”(在本例中为Animal)。 “接口”由Animal类声明的方法组成。
如果 bark()方法未在超类动物中定义,编译器会说:“嘿,这不起作用”。
这很有用,因为“有时候”我们在编码时会输入拼写错误(例如输入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是否是有效消息。
这是编译器说“嘿,我是程序员,我知道我在做什么”的指令。并且编译器,检查,Ok,dog,可以接收消息bark(),继续。然而,如果在运行时动物不是狗,则会引发运行时异常。
演员也可以缩写为:
if( a instanceof Dog ) {
((Dog)a).bark();
}
那将会运行。
所以,正确的答案是 4:“对树皮的调用导致编译时错误”
我希望这会有所帮助。