0

I am learning Java and as per knowledge I know that all objects are created at runtime when the function is called.

I came across these two examples which have let me to a confusion

Example 1:

class Animal { void jump() { System.out.println("Animal"); } } class Cat extends Animal { void jump(int a) { System.out.println("Cat"); } } class Rabbit extends Animal { void jump() { System.out.println("Rabbit"); } } public class Circus { public static void main(String args[]) { Animal cat = new Cat(); Rabbit rabbit = new Rabbit(); cat.jump(); rabbit.jump(); } } 

Output of this Code is:

Animal Rabbit

Example 2

class Employee { String name = "Employee"; void printName() { System.out.println(name); } } class Programmer extends Employee { String name = "Programmer"; void printName() { System.out.println(name); } } public class Office1 { public static void main(String[] args) { Employee emp = new Employee(); Employee programmer = new Programmer(); System.out.println(emp.name); System.out.println(programmer.name); emp.printName(); programmer.printName(); } } 

O/P of this example is

Employee Employee Employee Programmer

Now my question is why in example 1 cat.jump() is returning output as 'Animal' and in example 2 why programmer.printName() is returning 'Programmer'.

I think this has something to do with dynamic and static binding but I'm not able to understand how it is being implemented in these examples.

4
  • I'm going to reformat this, do you mind? Commented Jun 13, 2014 at 23:18
  • It's because of (int a) on jump in Cat. This makes it an entirely different jump method. For more information, you'll want to read some tutorials, such as the trail that starts here. Commented Jun 13, 2014 at 23:19
  • @AnubianNoob Sure please.... anything that can help me understand this concept Commented Jun 13, 2014 at 23:19
  • 1
    Next time, you should try to fix formatting and grammar errors yourself. This question was pretty good and shows effor, but badly asked. Next time, your question might not make up for its lack of clarity Just a friendly reminder. Commented Jun 13, 2014 at 23:22

3 Answers 3

3

It's easiest to think about this by copy/pasting inherited methods in your head.

The Cat class will look like this:

class Cat extends Animal { void jump() { System.out.println("Animal"); } // <-- Inherited from Animal void jump(int a) { System.out.println("Cat"); } } 

So when you call cat.jump(), the compiler sees that there is a no-args jump() method and binds Animal#jump() there.

Rabbit looks like this:

class Rabbit extends Animal { void jump() { System.out.println("Rabbit"); } // Overrides jump() from Animal } 

So for rabbit.jump() the compiler binds the only jump() available and dynamic polymorphism ensures that the Rabbit version is called.


Now, fields are not polymorphic, and are bound at compile time (if memory serves). Because the compiler works off the reference type of objects, the field bound will depend on the type of the reference, and not the type of the object.

Therefore, programmer.name actually refers to the name field of Employee, because the reference type of programmer is Employee. Because both employee and programmer have reference types of Employee, Employee will be printed.

As a side note, the name field in Programmer is hiding the name field that was inherited from Employee. Inside the Programmer class (for this references), the Programmer version of name will be used, but outside of Programmer the name field used will depend on the reference type you are using.

Methods are polymorphic, so the method that runs depends on the dynamic type of the object. Therefore, employee will call Employee#printName() and programmer will call Programmer#printName(), as those are the runtime types of those objects.

Sign up to request clarification or add additional context in comments.

Comments

0

Because in the first scenario, you have called jump() on a Cat object which inherits this method from its base class Animal.

I think you were expecting "Cat" to be output but this is not the case as you called jump(), not jump(int).

Comments

0

General information:

Java is Dynamic binding or late binding, this means that at runtime, the program will see if the method called is overridden by checking the dynamic type of the object and will call it. In other world, having:

Animal cat = new Cat(); cat.jump(); 

JVM at runtime, before calling jump() will look at the dynamic type of cat and it will notice that it is of dynamic type Cat. Therefore it will search in Cat if there exist an overriden method called jump(). If it finds it, it will use it, otherwise it will go up to the parent (Animal) and execute jump() from there.

Please note that static methods behave differently and are not overidden.

Back to your code behavior

In example 1, you are calling jump() and not jump(int n). In class Cat, you are overloading the method jump() and not overridding it. So if you try to call cat.jump(1); you will have as output Cat. Overloading a method will create an additional method with same method name but different different argument.

Putting all together

You are confusing 2 concepts, dynamic binding and Overloading vs Overriding. Java is dynamic binding, it will execute the method closest to the real type (dynamic type) of the object created. If a method was overriden by a child having this example: cat.jump() where cat has static type (Animal) and dynamic type (Cat), will execute the method jump() from the dynamic type Cat if found there, if not found it will execute it from the static type Animal.

Overriding a method is creating a method that already exist in a parent class inside a child class. (Here dynamic binding play it roles)

Overloading a method is creating a method that already exist in a parent class inside a child class but with different arguments. (This is why you are not getting Cat as output)

5 Comments

Hmmm, I learned that virtual calls in Java don't incur any performance penalty through searching as you seem to be implying. At least the decompiled bytecode seems to be calling Animal#jump() immediately...
Unlike c++ JAVA looks at the closest meaning of the object and will execute the closest method to the object. Scientifically speaking, it will look at the dynamic type Cat and check if jump() is there, if not call the parent method.
Yeah, I know how dynamic dispatch works. I'm just thought dynamic dispatch was implemented using a virtual method table or something instead of actively searching for the implementation at runtime, so deep inheritance hierarchies wouldn't incur a performance penalty.
@user3580294 Late binding affect the performance of the application because as you said it needs to search in the virtual table for the correct method to execute. I believe this is one of many things that makes Java slower than C++
But when everything is virtual (as in Java [until the JIT compiler gets to that method]), deep inheritance hierarchies won't matter. I do agree that virtual methods in general would affect performance though. So I don't really have anything to complain about except the way you said virtual methods are resolved.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.