Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is overriding toString() considered polymorphism?

I was having an exam in Java today and the examiner asked me if I can provide any examples of using polymorphism in my Spring Boot project.

As I couldn`t think of anything at first, he pointed out that I have overriden toString() in my models and that this is dynamic/runtime polymorphism.

However, I am not sure that I understand his point, because to my understanding, a behavior is considered polymorphmic when we have a parent class reference variable pointing to a subclass object (focusing on dynamic polymorphism).

Then at runtime the actual object, to which the parent class variable points to, is fetched and its method is called, as explained nicely here.

However, I do not use upcasting in my project (i.e. initializing my POJO classes with an Object class variable).

Thus, my question is - is overriding toString() considered polymorphism, although the parent class (Object) is never used as a reference variable?

All exampes of runtime polymorphism that I find on Stackoverflow, including the ones here and this one with toString, illustrate a situation where we have a parent class variable pointing to a subclass object, e.g:

    Object object = new User("petar");
    String name = object.toString(); // assign to variable for clarity`s sake
    System.out.println(name);
    // prints petar

Where my User class is:

public class User {

    String name;

    public User(String name) {
        this.name = name;
    }

    public String toString() {
        return name;
    }
}

However, in my project I simply create users and other POJO classes with their own reference variables, e.g:

    User user = new User("petar");
    String name = user.toString();
    System.out.println(name);
    // prints petar, as toString is overriden

Is the above considered polymorphism, although there is no upcasting / parent reference variable involved?

My classmate argues that it is, because for non-final instance methods, the compiler doesn`t know which method to call - it only ensures that there is such method in the superclass, so it prolongs this decision up until runtime (late binding) by inserting an instruction into the compiled code, which is checked then and the actual object, to which the variable points to, is fetched, and its method is called (source).

However, in this article it is stated that:

Method Overriding is an example of runtime polymorphism. When a parent class reference points to the child class object then the call to the overridden method is determined at runtime, because during method call which method(parent class or child class) is to be executed is determined by the type of object. This process in which call to the overridden method is resolved at runtime is known as dynamic method dispatch.

So: is method overriding sufficient for polymorphism, or is it a requirement that there is a parent class reference to the subclass object? Am I safe to say at interviews that merely overriding toString() is an example of polymorphism?

like image 488
Petar Bivolarski Avatar asked Nov 15 '22 18:11

Petar Bivolarski


1 Answers

Thanks to the comments and a few other sources, I believe I can now answer my question as follows:

One could argue that overriding toString() is an example of polymorphism because:

The Java Virtual Machine (JVM) always selects the method to invoke on non-final instance methods based on the object that it is referenced to, and not the method defined by the variable type. This is known as dynamic method invocation or late binding i.e - the decision which method to call happens at runtime, hence the wording "runtime" polymorphism. Source: Oracle Docs, JavaWorld.

Thus, regardless whether we consciously use polymorphism by e.g. programming to interfaces or we do a simple toString() method override, but still continue to use our classes with their own class variables (i.e. using a "User" variable instead of the parent class "Object" variable), a decision about which method to call is always made on runtime by checking the type of object our variables are referring to.

Thus, the evaluation on which model to call (i.e. the polimorphic behavior) happens, regardless which of the two initializations we use:

    User user = new User("username1");
    System.out.println(user);
    
    // or

    Object object = new User("username1");
    System.out.println(object);

The type of the variable is insignificant for our question, what matters is the object that it is referring to, and which of all possible objects it refers to (i.e a parent or a child), is decided on runtime.

The type of the variable is only relevant to either limit the scope of available methods to the ones in the parent class and potentially overridden by its children (if we use a parent class reference variable) or to gain access to the specific methods of the child (if we use a child class reference variable).

For example, if we added a new method to our User class:

    public String instanceMethod () {
    return "User instance method called";
}

It would not be available through a Object class variable:

enter image description here

It would only be available through a User class variable.

Hope this clears the confusion for everyone else that needs a more detailed explanation too.

like image 108
Petar Bivolarski Avatar answered Feb 02 '23 01:02

Petar Bivolarski