2

I know polymorphism happens in the case of method overriding. But I am a little confused about the below.

class A {
    public void hi() {
        System.out.println("A "+this.getClass().getName()); 
    }
}

class B extends A {
    public void bye() {
        System.out.println("B "+this.getClass().getName());
    }
}

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        A a = new B();
        a.hi();
        a.bye();
    }
}

Output:

Main.java:35: error: cannot find symbol
        a.bye();
         ^
  symbol:   method bye()
  location: variable a of type A
1 error

Why does this give a compile time error?

In a = new B(), the B class object is created at runtime, so a's a reference variable pointing to an object of type B.

Now if we call B's class method bye(), why it is a compiler time error?

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • Since you asked about how to call subclass methods via a superclass reference in one comment, I'll try to help you with an example: assume you're trying to talk to some person but you have no idea where they come from. So you'd know that because its a human there is the method `talkTo(me)` (which could throw an exception if the person is mute) but you don't know whether there are more specialized methods like `talkEnglishTo(me)` or `talkChineseTo(me)` - if you only know the superclass is `Person` you don't know whether it's actually an instance of subclass `ChinesePerson` etc. – Thomas Jun 16 '16 at 08:38

6 Answers6

2

The a variable may contain in run-time an instance of class A or any sub-class of A. Therefore, you can only call methods of class A for that variable.

The compiler only cares about the compile-time type of the variable when it determines which method calls are valid.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • :- Agree . but at compile time, it not create any object of class B. so we can say a.hi() is resolved at compile time ? –  Jun 16 '16 at 08:21
  • :- How can I call a.bye() using A class reference as above ? cloud you please explain. it is possible or not using this use case ? –  Jun 16 '16 at 08:24
  • 1
    @YogendraSharma At compile time the compiler determines that `A` (the compile type of `a`) has a `hi` method with no arguments, so that statement passes compilation. However, that method may be abstract and/or overridden by a sub-class. Only at run-time the actual method to be executed is chosen, based on the run-time type of `a`. – Eran Jun 16 '16 at 08:25
  • @YogendraSharma You can only call `bye` if you cast `a` to `B` : `((B)a).bye()`. Of course, you'd better check that `a instanceof B` before making that cast. – Eran Jun 16 '16 at 08:26
  • :- Got it.. Thanks –  Jun 16 '16 at 08:29
2

The declared type of the variable a is A. The compiler doesn't know (and shouldn't know) what its concrete type at runtime is B. All it knows is that it's a A, and that there is no bye() method in A.

The whole point of doing

A a = new B();

and not

B a = new B();

is to clearly say that a is a A, and could have any concrete type, as long as the conrete type extends A. You must be able, if you find a better implementation of A later, to just change that line to

A a = new BetterImplementation();

and have the code compile.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

Assigning the new B instance to a reference of type A is like making it wear the only-see-methods-defined-at-A glasses. That is you get the interface described at A. And even though that instance has an implementation for bye, you can only access hi.

0

An easy way to understand this is that A a might be actually pointing to the object of B, but during compile time the compiler doesn't know that.

The compiler only checks the reference i.e. 'a' and sees if its class , i.e. 'A' has the method that its reference 'a' is trying to call.

In your case, the reference 'a' does not have a method called bye() so according to the compiler such a call cannot be made and that is why you see that error.

yash sachdeva
  • 637
  • 5
  • 13
0

I think you have got the answer for your polymorphism problem from other answers. Addition to that, you can make your code work in this way with type casting.

(B)a.bye();

This is a good explanation for you to read about reference vs object types. And this is a good article about casting.

Community
  • 1
  • 1
Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
0

You can access parent class methods only from parent class type.

A a = new B();

Solution 1:

Change parent to child ( B b = new B ()) and call B methods.

Solution 2:

Check if parent is instance of Child object. If yes, cast the parent to Child and call the method.

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        A a = new B();
        a.hi();
        if ( a instanceof B){       
            ((B)a).bye();
        }
    }
}

output:

A B
B B

Have a look at oracle documentation page on instanceof

The instanceof operator compares an object to a specified type. You can use it to test if an object is an instance of a class, an instance of a subclass, or an instance of a class that implements a particular interface.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211