18

Animal 是 Dog 的超类,Dog 有一个叫做 bark 的方法

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

考虑以下:

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

会发生什么?

  1. 不允许分配
  2. 允许调用 bark 并在运行时打印“woof”
  3. 允许调用 bark,但没有打印任何内容
  4. 对 bark 的调用导致编译时错误
  5. 对 bark 的调用导致运行时错误

我说 2 因为我们正在检查对象是否是狗;因为 dog 是其中包含 bark 方法的类,如果是,则我们调用它,它将打印出:s

我的理解在这里正确吗?

4

9 回答 9

33

这不会编译,因为 Animal 没有名为 bark 的方法。这样想,所有的狗都是动物,但不是所有的动物都是狗。所有的狗都会吠叫,但并非所有的动物都会吠叫。

于 2009-05-22T17:08:45.327 回答
27

否 - 答案是;

4) 调用 bark 导致编译时错误

bark 方法未定义为分配类型 Animal 上的方法,因此将导致编译时问题;这可以通过铸造来解决;

((Dog)a).bark();
于 2009-05-22T17:10:13.907 回答
12

关键在以下行:

Animal a = new Dog();

尽管创建了 的新实例Dog,但它的引用被a声明为 type Animal。因此,任何对 的引用a都会将new Dog其作为Animal.

因此,除非Animalbark方法,否则以下行将导致编译器错误:

a.bark();

即使a经过测试以查看它是否是 的实例Dog,并且a instanceof Dog实际上会返回true,但变量a仍然是 is 类型Animal,因此if语句内的块仍然a作为Animal.

这是静态类型语言的一个特性,其中变量被提前分配类型,并在编译时检查以查看类型匹配。如果此代码是在动态类型语言上执行的,在运行时检查类型,则可能允许以下内容:

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

a.bark()保证仅在实例为 a 时执行Dog,因此对的调用bark将始终有效。但是,Java 是一种静态类型的语言,因此不允许使用这种类型的代码。

于 2009-05-22T17:11:20.130 回答
6

Head First Java中,他们使用电视遥控器的非常好的类比作为参考,并将您的电视作为参考指向的对象。如果你的遥控器只有开、关、频道上下以及音量上下的按钮(方法),那么你的电视有什么很酷的功能并不重要。你仍然只能从遥控器上做那几件基本的事情。例如,如果您的遥控器没有静音按钮,您就无法将电视静音。

Animal 参考只知道 Animal 方法。不管底层对象有什么其他方法,你都不能从 Animal 引用中访问它们。

于 2009-05-22T17:19:36.860 回答
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();
}  

这会将超类转换回子类并打印它。尽管它的设计很糟糕,但它是动态知道它指向哪个子类对象的一种方法。

于 2011-05-12T21:06:12.673 回答
4

是 4。你不能要求一个通用的 Animal ——这就是你的代码所说的 a ——吠叫。因为你可以很容易地说

Animal a = new Cat();

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

于 2009-05-22T17:10:14.967 回答
3

在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 没有任何树皮方法,因此调用了超类的方法。它将第一行写入控制台。Dog 有一个 bark 方法,所以超类调用它。它将第二行写入控制台。

于 2014-05-04T14:52:40.200 回答
2

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

几乎任何时候你都有这种形式的代码:

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

您正在滥用类型系统。这不是使用类的方式,也不是编写可维护的面向对象代码的方式。它很脆。很复杂。这不好。

您可以在基类中创建模板方法,但它们必须调用存在于基类中并在子类中被覆盖的方法。

于 2009-05-22T17:41:56.970 回答
1

“我说 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 的调用导致编译时错误

我希望这有帮助。

于 2009-05-22T17:38:39.423 回答