Polymorphism


In order to run a program in java, we need to compile with javac and then run the program with java. The compiler checks for syntax errors while runtime JVM checks for logic errors.

When we create a Student object with the following:

        Student s = new Student();

We can see that there are two \"datatypes\" present in the statement. The Student on the left-hand side is called the static type of the variable; the new Student on the right is the dynamic type of the variable.

Static type:

During compile time, the compiler sees everything as its static type. As an analogy, each object is like a box of content, the static type of the object is like a label on the box so that the compiler can simply check what the label is without looking into the box for faster processing. Casting can change the static type of an object temporary, what does that mean? Let’s use the student object above. If we ask what the static type of the variable s is, we know that it is a Student type. However, when we cast like the following:

                 (Object)s

     

From the compiler’s perspective the expression together has a static type of Object. That being said, if we ask what the static type of s, it remains as Student. Hence, casting changes the static type of an object temporarily when the casting is applied.

Dynamic type:

Dynamic type is what type of object is actually created. Every object is seen as its dynamic type during run time. In the analogy, the dynamic type of the object is the content actually in the box. You can never change a dynamic type of an object.

Let’s do a few example:
Assume Student extends Person

Code Static type Dynamic type
new Student() Student Student
Person p = new Student() Person Student
Object o = new Student() Object Student
Object object = (Person) new Student()
type of object?
Object Student

Dynamic Method Binding

This concept, in short, only means that when you are calling an instance method on an object, assuming that it compiles and runs with no errors, java will pick the method used based on the dynamic type object. For example, let us have the following:
Assume Cookout, Salad, Bento all extends Food and have a getCalories method.

             Food cookout = new CookOut();
        Food salad = new Salad();
        Food bento = new Bento();

       

We can see that all three objects have the same static type but different dynamic types. If we call getCalories on all three objects, it wouldn’t make sense for all three objects to return the same calories. It would make more sense to get the calories of what the object actually is. Therefore, the method being called will be based on the dynamic type of the variable.

Important: Evaluation of Polymorphism

To evaluate each expression, first determine that whether it passes the compile tests, and then check if it violates logic error during runtime. If both of them passes, you then determine which method is being used.

polymorphism example

Keep in mind that you will need to come up with a class diagram when you encounter a polymorphism problem, a class diagram will make your life a lot easier.

1. Animal a = new Dog();

During assignments, we have to follow the rule that the static type of right hand-side must be the same or sub class of the left hand-side. We can see that Dog is a subclass of Animal, so the expression is valid.

2. Chihuahua d = new Dog();

Building from the previous question, notice that Dog is a super class of Chihuahua. This can be caught during compile time. Hence you would write Compile error, cannot assign Dog to Chihuahua As your answer.

3. Animal a = new Dog();
     a.bark();

This is where it starts to get a bit tricky. In the first line, we are assigning a Dog to an Animal, so that’s fine, at the second line we see that it is trying to call bark method on variable a. Remember that during compile time, everything is seen as its static type. As far as the compiler’s concern, a is of type Animal. The compiler takes a look at the animal class and wonder: “ does it have a bark method?” it does not, hence it would cause a compile error. As a developer, we know that variable a is a dog and dog has a bark method, but since you can’t get pass the compiler, the code still fails. On the test, we would write, Compile error, cannot find method bark. How do we fix this issue? Recall that the issue is raise because of the static type of a is an Animal, we just need to “promise” java that variable a is a type of dog by casting. Hence the following would fix. ((Dog)a).bark(); In which case would execute the bark method in Dog class.

4. Animal a = new Animal();

Both static type and dynamic type are Animal, which works, although Animal is an abstract class and recall that you cannot instantiate an abstract class. Hence the code fails. Compile error, cannot instantiate Animal object.

5. Shiba s = new Shiba();
     Bichon b = (Bichon) s;

While casting, you can cast a data type to its parent or child. However, you cannot cast sideways. In class diagram we can see that Shiba and Bichon are siblings’ classes. You are essentially promising java that the Shiba is a Bichon, and from Java’s perspective, it’s simply impossible, hence the compiler doesn’t like it and throw an error. Compile error, cannot convert Shiba to Bichon( or cannot cast sideways)

6. Dog d = new Dog();
     Turtle t = (Turtle) d;

First line is fine, the second line has the same issue as the previous question, you are trying to cast Dog to a Turtle and it is sideways and cannot be converted. Compile error, cannot convert Dog to Turtle(cannot cast sideways)

7. Animal b = new Dog();
     Turtle t = (Turtle) b;

In the first line, you assign a Dog to an Animal, which is fine. However, in the second line, you cast b to Turtle. Notice that although this question is very similar to the previous two, but it is very different. Note that b at compile time has a static type of Animal, hence, casting an Animal to Turtle is fine during compile time. You are promising compiler that “hey, no need to look at the content just yet, I promise you that the object is a type of Turtle. Without seeing dynamic type of the object, the compiler believed you. Now during runtime, everything now is seen as the dynamic type. Now java sees that previous you promised that the object is a Turtle, but it is actually a Dog. Hence java revenges you by breaking you program. Please analyze carefully the difference between this question and the previous question. Runtime error, ClassCastException(or cannot convert a Dog to Turtle)

8. Bichon d1 = new Bichon();
     d1.bark();

First line is fine, in second line, compiler checks whether Bichon has a bark and it does. Hence, we would execute Bichon’s bark method. No error, Bichon’s bark.

9. Dog d = new Dog();
     d.bark();

Similar to the last question. The method will execute based on the dynamic type of the object. No error, Dog’s bark.

10. Dog d = new Bichon():
     d.bark();

Both lines compiles and run without error. Dynamic method binding tells us that we would execute the dynamic type’s method. Hence Bichon’s bark will be used. No error, Bichon’s bark.

11. Dog d = new Bichon();
     ((Dog)d).bark();

Does casting change the outcome of this question? Note that in this question, we cast d to Dog and tried to execute the bark method. Since Dog has a bark method, it compiles and runs just fine. Again, the method chosen is based on the dynamic type of the object. Hence bichon’s bark is still used. Casting doesn’t change anything. No error, Bichon’s bark.