1

I'm studying Java and I was given the following code:

public class A {
    public void m(A a) { System.out.println("A.m:A"); }
    public void m(B b) { System.out.println("A.m:B"); }
}

public class B extends A {
    private void m(C c) { System.out.println("B.m:C"); }
    public void m(B b) { System.out.println("B.m:B"); }
}

public class C extends A {
    public static void main(String args[]) {
        A ab = new B();
        B bb = new B();
        A ac = new C();

        ab.m(ac); // My answer: A.m : A || correct
        ab.m(ab); // My answer: B.m : B || Correct answer: A.m : A
        ab.m(bb); // My answer: B.m : B || correct
        bb.m(ac); // My answer: compile error || Correct answer: A.m : A
        bb.m(ab); // My answer: B.m : B || Correct answer: A.m : A
        bb.m(bb); // My answer: B.m : B || correct
        ac.m((A)bb); // My answer: A.m : A || correct
        bb.m((B)ac); // My answer: compile error || Correct answer: run-time error [Class cast exception] --> I UNDERSTAND THIS
        bb.m((B)ab); // My answer: B.m : B || correct
    }
}

I had to write what would be the result of the calls in main function. As you can see I got most answers wrong. What I'm trying to understand is how can I determine what class function is called when I have a variable of the type of the superclass that is created with the constructor of a subclass?

tropicaldc
  • 13
  • 3
  • 1
    Possible duplicate of [Java dynamic binding and method overriding](http://stackoverflow.com/questions/321864/java-dynamic-binding-and-method-overriding) – Seelenvirtuose May 20 '17 at 16:30

2 Answers2

0

In order to answer questions of this kind, you need to consider three things:

  1. What is run-time type of the object on which you call the method?
  2. What is compile-time type of method's argument?
  3. Would there be errors in argument conversions, if any?

To answer (1) look at the right side of the declaration: ab and bb are of type B, while ac is of type C.

To answer (2) look at the left side of the declaration: ab is an A, bb is a B, and ac is an A.

To answer (3), look for casts, and compare to the type from part (1). Converting a subclass to a base class is allowed, as in (A)bb. However, converting between siblings, as in (B)ac, causes compile-time errors when compile-time type lets you determine that you are converting a sibling, or run-time errors when compile-time type is of a parent.

Once you have answers to (1) and (2), and eliminated errors caused by (3), you need to look at the source code, and pick method overload of the class from (1) that matches the type of the class from (2).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

The above answer makes perfect sense, so I am not going to repeat what that user has already said. The scenarios where your answers are incorrect (other than the one you mentioned that you already understood) are all related to passing a super class object created with sub class implementation as argument to the method m.

A ab = new B();
B bb = new B();
A ac = new C();

ab.m(ab); // My answer: B.m : B || Correct answer: A.m : A
bb.m(ac); // My answer: compile error || Correct answer: A.m : A
bb.m(ab); // My answer: B.m : B || Correct answer: A.m : A

In all these statements above, you are actually passing an object of A though the implementation is of sub class. So without any further confusion, you can look for the method who is taking the parameter of object A. Because the actual object implementation can be resolved only at run time.

ayip
  • 2,473
  • 1
  • 19
  • 30