简体   繁体   中英

Subclass object with superclass funcionality

I'm confused why this code works. The object "person" is declared as an instance of B with only the functionality of A, yet it somehow prints out hello twice. If the object only gets access to the methods in A, how can it end up accessing the print out statement?

abstract class A {
  abstract void move();
    void go() {
      this.move();
    }
}
class B extends A {
    void move() {
        System.out.println("hello");
    }
}
public class Main {
 public static void main(String[] args){
   A person = new B();
   person.move();
   person.go();
 }

No, you have a "link" of class A, but functionality depends on object (in your code it is new B();), so your A link points to a B object with B functionality.

The object "person" is declared as an instance of B with only the functionality of A

Not exactly. Java is a reference-based language; here you have made an instance ( new B() ), and have exactly one reference to it, called person .

You could have no references to it (leading to the created object being garbage collected eventually). You can have 2000 references to it. You could have B b = new B(); A a = b; B b = new B(); A a = b; , and now you have 2 references to it, one of type A and one of type B . But they are pointing to the exact same object.

Thus, person isn't an object, it's a reference. And that reference has type A , sure, but the object it is referencing is just a B, it isn't 'restricted' to have only A functionality.

You probably know all this, but terminology is important here, as it seems to have led to some confusion. Restating your question with less ambiguous terminology:

The reference "person" currently references an instance of B, but only exposes functionality that A has.

Yes. And A's functionality is described solely by the signatures present there, not by the code. A's functionality involves having a go() method, which takes no arguments and returns nothing, as well as a move() method with the same rules. And that is all - 'invoking go will actually run the move method', or 'move has no implementation' is not part of that .

Thus, both move() and go() are part of the functionality exposed by A.

The implementation of the functionality has nothing whatsoever to do with the reference type ( A person ) and everything to do with what the reference is actually pointing at ( new B() ). B's implementation of the move() and go() methods specified by A are such that move prints "hello", and go() calls move (thus, prints hello()) - that implementation is inherited from A, but B was free to change that; B however decided not to.

Said more technically:

Java uses something called dynamic dispatch . What that means is that at compile time (ie write time), java figures out if a method you're calling even exists and which variant (if you have move(String a) and move(int a) , that's two methods with the same name, at write time java decides which one you are attempting to invoke), and uses the type of the expression in front of the dot to figure that out. But then at runtime, the actual type of the object that 'the expression in front of the dot' is actually pointing at is used to figure out which actual code to invoke. This always happens and you can't opt out (you can't choose to run A's implementation when you invoke main() . Only B's implementation can choose to not override A's implementation, or to explicitly invoke its supertype's implementation. A user of B's code cannot do that).

Note that static stuff doesn't 'do' inheritance at all, and therefore, dynamic dispatch doesn't apply there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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