简体   繁体   English

是否可以在超类对象上调用子类的方法?

[英]Is it possible to call subclasses' methods on a superclass object?

Animal is a superclass of Dog and Dog has a method called bark 动物是狗和狗的超类有一种叫做树皮的方法

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

Consider the following: 考虑以下:

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

What will happen? 会发生什么?

  1. the assignment isn't allowed 不允许转让
  2. the call to bark is allowed and "woof" is printed at run time 允许对树皮的调用,并在运行时打印“woof”
  3. the call to bark is allowed but nothing is printed 允许吠叫,但没有打印
  4. the call to bark causes a compile time error 对bark的调用会导致编译时错误
  5. the call to bark results in a run time error 对bark的调用导致运行时错误

I said 2 as we are checking if the object is a dog; 当我们检查对象是否是狗时,我说2; as dog is the class with the bark method in it, if it is then we call it which will print out :s 因为狗是带有树皮方法的类,如果是,那么我们称它为打印出来的:s

Is my understanding correct here? 我的理解在这里是否正确?

This won't compile since Animal does not have a method called bark. 这将无法编译,因为Animal没有名为bark的方法。 Think of it this way, all dogs are animals, but not all animals are dogs. 想一想,所有的狗都是动物,但不是所有的动物都是狗。 All dogs bark, but not all animals bark. 所有的狗都吠叫,但不是所有的动物都吠

no - the answer is; 不 - 答案是;

4) the call to bark causes a compile time error 4)对bark的调用导致编译时错误

the bark method isnt defined as a method on the assigned type Animal, which will therefore result in compile time issue; bark方法没有被定义为赋值类型Animal的方法,因此会导致编译时间问题; this could be solved by casting; 这可以通过铸造来解决;

((Dog)a).bark();

The key is in the following line: 关键在于以下行:

Animal a = new Dog();

Although a new instance of Dog was created, its reference is by a which is declared to be of the type Animal . 虽然新实例Dog被创建,它的参考是由a被声明为类型的Animal Therefore, any references to a makes the new Dog be handled as an Animal . 因此,对a任何引用都会使new Dog被处理为Animal

Therefore, unless Animal has a bark method, the following line will cause a compiler error: 因此,除非Animal具有bark方法,否则以下行将导致编译器错误:

a.bark();

Even though a is tested to see if it is an instance of Dog , and a instanceof Dog will actually return true , the variable a is still of is of type Animal , so the block inside the if statement still handles a as an Animal . 即使a测试,看它是否是一个实例Dog ,和a instanceof Dog实际上将返回true ,变量a是仍是类型的Animal ,所以内部的块if语句仍然处理a作为Animal

This is a feature of statically-typed languages where variables are assigned a type ahead of time, and checked at compile-time to see that the types match. 这是静态类型语言的一个特性,其中变量被提前分配一个类型,并在编译时检查以查看类型是否匹配。 If this code were performed on a dynamically-typed language , where the types are checked at runtime, something like the following could be allowed: 如果此代码是在动态类型语言上执行的,那么在运行时检查类型,可以允许以下类似的内容:

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

a.bark() is guaranteed only to execute when the instance is a Dog , so the call to bark will always work. 保证a.bark()仅在实例为Dog时执行,因此对bark的调用将始终有效。 However, Java is a statically-typed language, so this type of code is not allowed. 但是,Java是一种静态类型的语言,因此不允许使用这种类型的代码。

In Head First Java they use the very good analogy of a TV remote control for a reference and your TV as the object that the reference points to. Head First Java中,他们使用电视遥控器的非常好的类比作为参考,并将电视作为参考指向的对象 If your remote only has buttons (methods) for on, off, channel up and down, and volume up and down, it doesn't matter what cool features your TV has. 如果你的遥控器只有按钮(方法)可以打开,关闭,频道上下,以及音量增大和减小,那么电视的酷炫功能并不重要。 You can still only do those few basic things from your remote. 您仍然只能从遥控器上执行这些基本操作。 You can't mute your TV, for example, if your remote has no mute button. 例如,如果遥控器没有静音按钮,则无法将电视静音。

The Animal reference only knows about Animal methods. Animal参考只知道动物方法。 It doesn't matter what other methods the underlying object has, you can't access them from an Animal reference. 底层对象具有哪些其他方法并不重要,您无法从Animal引用访问它们。

If the idea is to print the subclass method from superclass object, this will work: 如果想要从超类对象打印子类方法,这将工作:

Instead of 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){ a.bark(); } change to Animal a = new Dog(); if (a instanceof Dog){ a.bark(); }变化

Animal a = new Dog();

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

This casts the superclass back to subclass and prints it. 这会将超类强制转换为子类并将其打印出来。 although its bad design, its one way to know which child class object its pointing to dynamically. 虽然它的设计很糟糕,但它有一种方法可以知道动态指向哪个子类对象。

It's 4. You can't ask a generic Animal - which is what your code says a is - to bark. 它是4.你不能要求一个通用的动物 - 这是你的代码所说的 - 是吠叫。 Because you could just as easily have said 因为你可以很容易地说

Animal a = new Cat();

and the bark line doesn't have a way to know that you didn't. 并且树皮线没有办法知道你没有。

In java(only language i know) you can create an empty method and call it in super class. 在java(我知道的语言)中,您可以创建一个空方法并在超类中调用它。 Then you can override it in subclass to do whatever you want. 然后你可以在子类中覆盖它来做任何你想做的事情。 This way the super class calls its subclass' method. 这样超类就会调用它的子类'方法。

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(){
    }
}

This code calls an object of Snake then calls an object of Dog. 此代码调用Snake的对象然后调用Dog的对象。 It writes this to console: 它将此写入控制台:

this animal can't bark
Woof

Snake doesn't have any bark method so super class' method is called. Snake没有任何树皮方法,所以称为超级方法。 It writes the first line to the console. 它将第一行写入控制台。 Dog has a bark method so super class calls it instead. 狗有一种树皮方法,所以超类叫它。 It writes the second line to the console. 它将第二行写入控制台。

FYI, this is not a good design. 仅供参考,这不是一个好的设计。

Just about any time you have code of this form: 几乎任何时候你都有这种形式的代码:

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

you are abusing the type system. 你在滥用类型系统。 This is not the way to use classes, it's not the way to write maintainable object oriented code. 这不是使用类的方法,它不是编写可维护的面向对象代码的方法。 It's brittle. 它很脆弱。 It's convoluted. 这是令人费解的。 It's bad. 这不好。

You can create template methods in a base class, but they have to call methods that exist in the base class and are overridden in sub-classes. 您可以在基类中创建模板方法,但是它们必须调用基类中存在的方法并在子类中重写。

"I said 2 as we are checking if the object is a dog; as dog is the class with the bark method in it, if it is then we call it which will print out :s" “我说2,因为我们正在检查对象是否是狗;因为狗是带有树皮方法的类,如果是,那么我们称它为打印输出:s”

Your rationale is correct, but that's not the way it works. 你的理由是正确的,但这不是它的工作方式。

Java is an static typed language that means, the validity of the methods an object may respond to is verified at compile time . Java是一种静态类型语言,这意味着在编译时验证对象可能响应的方法的有效性。

You may think the check: 您可以考虑检查:

if( a instanceof Dog ) 

Would do, but actually it doesn't. 会这样做,但事实上并非如此。 What the compiler do is check against the "interface" of the declared type ( Animal in this case ). 编译器所做的是检查声明类型的“接口”(在本例中为Animal)。 The "interface" is composed of the methods declared on the Animal class. “接口”由Animal类声明的方法组成。

If the bark() method is not defined in the super class Animal the compiler says: "Hey, that won't work". 如果没有在超类Animal中定义bark()方法,那么编译器会说:“嘿,那不行”。

This is helpful, because "sometimes" we make typos while coding ( typing barck() instead for instance ) 这很有用,因为“有时”我们在编码时会输入拼写错误(例如输入barck())

If the compiler doesn't not warn us about this, you would have to find it at "runtime" and not always with a clear message ( for instance javascript in IE says something like "unexpected object" ) 如果编译器没有警告我们这一点,你必须在“运行时”找到它并且不总是有一个明确的消息(例如IE中的javascript说“意外对象”之类的东西)

Still, static typed language like java allow us to force the call. 尽管如此,像java这样的静态类型语言允许我们强制调用。 In this case it is using the "cast" operator () 在这种情况下,它使用“强制转换”运算符()

Like this 像这样

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

In line 3 your are "casting" to a Dog type so the compiler may check if bark is a valid message. 在第3行中,您正在“转换”为Dog类型,因此编译器可以检查bark是否是有效消息。

This is an instruction to to compiler saying "Hey I'm the programmer here, I know what I'm doing". 这是编译器说“嘿,我是程序员,我知道我在做什么”的指令。 And the compiler, checks, Ok, dog, can receive the message bark(), proceed. 并且编译器,检查,Ok,dog,可以接收消息bark(),继续。 Yet, if in runtime the animal is not a dog, a runtime exception will raise. 然而,如果在运行时动物不是狗,则会引发运行时异常。

The cast could also be abbreviated like: 演员也可以缩写为:

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

That will run. 那将会运行。

So, the correct answer is 4: " the call to bark causes a compile time error " 所以,正确的答案是4:对树皮的调用导致编译时错误

I hope this helps. 我希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM