4

With this code:

public abstract class A {
    private String runNow() {
        return "High";
    }

    public abstract String cos();

    static class B extends A {
        public String runNow() {
            return "Low";
        }

        public String cos() {
            return "cos from B";
        }
    }

    public static void main(String args[]) {
        A[] a = new B[] {new B(), new C()};
        for (A aa : a) {
            System.out.println(aa.runNow() + " " + aa.cos());
        }
    }
}

class C extends A.B {
    public String runNow() {
        return "Out";
    }

    public String cos() {
        return "cos from C";
    }
}

Why is the runNow method from class A invoked and not from the subclasses?

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
MGorgon
  • 2,547
  • 23
  • 41
  • 1
    possible duplicate of [Overriding private methods in Java](http://stackoverflow.com/questions/2000137/overriding-private-methods-in-java) – Tom Jul 12 '15 at 13:55
  • 1
    Please read the duplicated question about why you can't override private methods. And next time: annotate your methods with `@Override` so the compiler can check if you _really_ override a method or not. – Tom Jul 12 '15 at 13:56
  • 1
    please don't edit your question to introduce syntax errors. You can't name your `A[]` array `aa`. – Tom Jul 12 '15 at 14:04

5 Answers5

2

Short answer is "because runNow() is private".

When you compile this call aa.runNow() the compiler sees that class A has runNow method which is private, and that your code is calling this private method. Since private methods cannot be overriden, the compiler routs the call to A's runNow() method - the only one it knows to exist in this context.

The fact that B and C also introduce their methods by the same name does not matter to the compiler, because these methods are new in the subclasses. The compiler cannot consider them overrides without breaking encapsulation of class A, which designated runNow a private method.

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

It is because runNow() is a private method in class A. Private methods are not inherited so could not be overridden.

private String runNow(){
      return "High";
 }

And also that you have created a reference of type A

A[] a=new B[]{new B(),new C()};

so the only runNow() which will be called to complete the call is of class A as the compiler does not know about runNow() methods in class B and C

Lalit Mehra
  • 1,183
  • 1
  • 13
  • 33
1

It's because method runNow() in class A is private, so in classes B and C you're not overriding it. And when you're calling method aa.runNow() it's called directly from class A.

Try to do some experiment and change your method in class A to this:

private String runNow2() {
    return "High";
}

public String runNow() {
    return "High";
}

Also change your System.out to this one:

System.out.println(aa.runNow() + " " + aa.cos() + " " + aa.runNow2());

Now the result will be as expected.

Hope it helps!

Zano
  • 99
  • 1
  • 9
1

Why is the runNow method from class A invoked and not from the subclasses

private methods are not inherited in subclasses. Therefore, they cannot be overriden. Since runtime-polymorphism only applies to overriden methods, the runNow method from A will always be called. Change the runNow method in A to a public method and you will get the desired output since public methods are inherited and can be overriden.

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
1

As you were already told, the problem is that runNow() is private. It is therefore not overridden, and accessing it through a reference of type A would get you to the A class's definition, whereas trying to access it through a B reference would get the subclasses.

I would like to point out, though, that this "odd" behavior is only possible because the method that is doing all this (your main method) is defined inside A. If your main method was in another class that has access to these classes, you'd get an error that indicates that the method is not reachable at all. If you think about that, it may be more clear to you why the methods runNow() in B and C do not override the one in A. From the point of view of any object outside of A, there is no runNow() method at all - it's an implementation detail and not part of the contract of A. Therefore, it cannot be overridden, and the runNow() in B and C are just new methods that you don't have access to when you use B and C polymorphically as A.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79