Polymorphism

Learning about the concept of polymorphism in Java.

Polymorphism Interview with follow-up questions

Question 1: What is polymorphism in Java?

Answer:

Polymorphism in Java is the ability of an object to take on many forms. It allows objects of different classes to be treated as objects of a common superclass. This means that a variable of a superclass type can refer to an object of any subclass of that superclass.

Back to Top ↑

Follow up 1: Can you provide an example of polymorphism?

Answer:

Sure! Here's an example:

class Animal {
    public void makeSound() {
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Dog is barking");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("Cat is meowing");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();

        animal1.makeSound(); // Output: Dog is barking
        animal2.makeSound(); // Output: Cat is meowing
    }
}

In this example, the Animal class is the superclass, and the Dog and Cat classes are subclasses. The makeSound() method is overridden in each subclass, allowing the objects to behave differently when the method is called.

Back to Top ↑

Follow up 2: What are the types of polymorphism in Java?

Answer:

There are two types of polymorphism in Java:

  1. Compile-time polymorphism (also known as method overloading): This occurs when there are multiple methods with the same name but different parameters in a class. The appropriate method is chosen at compile-time based on the arguments provided.

  2. Runtime polymorphism (also known as method overriding): This occurs when a subclass provides its own implementation of a method that is already defined in its superclass. The appropriate method is chosen at runtime based on the actual type of the object.

Back to Top ↑

Follow up 3: How is polymorphism implemented in Java?

Answer:

Polymorphism in Java is implemented through method overriding and method overloading.

Method overriding is used to achieve runtime polymorphism. It allows a subclass to provide a different implementation of a method that is already defined in its superclass. To override a method, the subclass must have the same method signature (name and parameters) as the superclass method.

Method overloading is used to achieve compile-time polymorphism. It allows a class to have multiple methods with the same name but different parameters. The appropriate method is chosen at compile-time based on the arguments provided.

Back to Top ↑

Follow up 4: What is the advantage of polymorphism?

Answer:

The advantage of polymorphism in Java is that it allows for code reusability and flexibility. By treating objects of different classes as objects of a common superclass, you can write code that is more generic and can work with a variety of objects. This makes the code easier to maintain and enhances its flexibility, as new subclasses can be added without modifying the existing code.

Back to Top ↑

Question 2: What is the difference between static and dynamic polymorphism?

Answer:

Static polymorphism, also known as compile-time polymorphism, is a mechanism in which the compiler determines which function to call based on the static types of the arguments and the function signature. This is achieved through function overloading and operator overloading.

Dynamic polymorphism, also known as runtime polymorphism, is a mechanism in which the compiler determines which function to call based on the dynamic type of the object at runtime. This is achieved through function overriding and virtual functions.

Back to Top ↑

Follow up 1: Can you provide an example of static and dynamic polymorphism?

Answer:

Sure! Here's an example of static polymorphism:

#include 

class Shape {
public:
    void draw() {
        std::cout << "Drawing a shape" << std::endl;
    }
    void draw(int x) {
        std::cout << "Drawing a shape with size " << x << std::endl;
    }
};

int main() {
    Shape shape;
    shape.draw();
    shape.draw(10);
    return 0;
}

And here's an example of dynamic polymorphism in C++ using inheritance and virtual functions:

#include 

class Shape {
public:
    virtual void draw() {
        std::cout << "Drawing a shape" << std::endl;
    }
};

class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a circle" << std::endl;
    }
};

int main() {
    Shape* shape = new Circle();
    shape->draw();
    delete shape;
    return 0;
}
Back to Top ↑

Follow up 2: When would you use static polymorphism over dynamic and vice versa?

Answer:

Static polymorphism is useful when the behavior of a function can be determined at compile-time based on the static types of the arguments. It can lead to more efficient code execution as the function call is resolved at compile-time.

Dynamic polymorphism is useful when the behavior of a function needs to be determined at runtime based on the dynamic type of the object. It allows for more flexibility and extensibility in the code, as different derived classes can override the base class function to provide their own implementation.

Back to Top ↑

Follow up 3: How does Java handle dynamic method dispatch?

Answer:

In Java, dynamic method dispatch is achieved through the use of virtual functions and method overriding. When a method is declared as virtual in the base class, it can be overridden by derived classes. The actual method to be called is determined at runtime based on the dynamic type of the object.

Here's an example in Java:

class Shape {
    public void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape shape = new Circle();
        shape.draw();
    }
}
Back to Top ↑

Question 3: What is method overloading and method overriding?

Answer:

Method overloading is a feature in object-oriented programming where multiple methods can have the same name but different parameters. Method overriding is a feature that allows a subclass to provide a specific implementation of a method that is already defined in its superclass.

Back to Top ↑

Follow up 1: Can you provide an example of method overloading and method overriding?

Answer:

Sure! Here's an example of method overloading:

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

In this example, the Calculator class has two add methods with the same name but different parameter types. The first add method takes two integers as parameters and returns an integer, while the second add method takes two doubles as parameters and returns a double.

And here's an example of method overriding:

public class Animal {
    public void makeSound() {
        System.out.println("The animal makes a sound.");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("The dog barks.");
    }
}

In this example, the Animal class has a makeSound method, and the Dog class overrides this method to provide a specific implementation for dogs.

Back to Top ↑

Follow up 2: What are the rules for method overloading and method overriding?

Answer:

The rules for method overloading are as follows:

  1. The methods must have the same name.
  2. The methods must have different parameter types or a different number of parameters.
  3. The methods may have different return types, but it is not a determining factor for overloading.

The rules for method overriding are as follows:

  1. The method in the subclass must have the same name, return type, and parameters as the method in the superclass.
  2. The method in the subclass must be declared with the @Override annotation.
  3. The method in the subclass must have the same or a more accessible access modifier than the method in the superclass.
  4. The method in the subclass must not throw a checked exception that is not declared by the method in the superclass.
Back to Top ↑

Follow up 3: How do method overloading and method overriding support polymorphism?

Answer:

Method overloading and method overriding both support polymorphism, which is the ability of an object to take on many forms. Polymorphism allows objects of different classes to be treated as objects of a common superclass.

Method overloading supports polymorphism by allowing different methods with the same name to be called based on the type and number of arguments passed to them. This allows for more flexibility and convenience when working with objects of different types.

Method overriding supports polymorphism by allowing a subclass to provide a specific implementation of a method that is already defined in its superclass. This allows for specialization and customization of behavior for different types of objects while still maintaining a common interface.

Back to Top ↑

Question 4: What is the role of the 'super' keyword in relation to polymorphism?

Answer:

The 'super' keyword in Java is used to refer to the superclass of a subclass. It is used to access the members (methods and variables) of the superclass from within the subclass. The 'super' keyword is particularly useful in cases where the subclass overrides a method or hides a variable of the superclass, and we want to access the superclass version of the method or variable.

Back to Top ↑

Follow up 1: Can you provide an example where 'super' keyword is used?

Answer:

Sure! Here's an example:

public class Animal {
    public void makeSound() {
        System.out.println("Animal is making a sound");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        super.makeSound();
        System.out.println("Dog is barking");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.makeSound();
    }
}

In this example, the 'super' keyword is used in the makeSound() method of the Dog class to call the makeSound() method of the superclass Animal. This allows the Dog class to inherit and extend the behavior of the Animal class.

Back to Top ↑

Follow up 2: What happens if we do not use 'super' keyword?

Answer:

If we do not use the 'super' keyword, the subclass will override or hide the method or variable of the superclass. This means that when the subclass is used, the overridden or hidden version of the method or variable will be used instead of the superclass version. This can lead to unexpected behavior and can prevent the subclass from accessing or utilizing the functionality provided by the superclass.

Back to Top ↑

Follow up 3: Can 'super' keyword be used with methods, variables, and constructors?

Answer:

Yes, the 'super' keyword can be used with methods, variables, and constructors. When used with methods, it allows the subclass to call and invoke the superclass version of the method. When used with variables, it allows the subclass to access the superclass version of the variable. When used with constructors, it allows the subclass constructor to call and invoke the superclass constructor.

Back to Top ↑

Question 5: What is 'upcasting' and 'downcasting' in Java?

Answer:

'Upcasting' and 'downcasting' are two concepts in Java that are used to convert an object from one type to another.

'Upcasting' is the process of converting an object of a subclass to its superclass type. This is done implicitly and does not require any explicit casting. For example, if we have a class hierarchy where 'Dog' is a subclass of 'Animal', we can upcast a 'Dog' object to an 'Animal' object like this:

Animal animal = new Dog();
Back to Top ↑

Follow up 1: Can you provide an example of 'upcasting' and 'downcasting'?

Answer:

Sure! Here's an example of 'upcasting' and 'downcasting' in Java:

// Upcasting
Animal animal = new Dog();

// Downcasting
Dog dog = (Dog) animal;
Back to Top ↑

Follow up 2: What is the use of 'upcasting' and 'downcasting'?

Answer:

'Upcasting' is useful when we want to treat an object of a subclass as an object of its superclass. This allows us to access only the common methods and fields defined in the superclass, while hiding the specific implementation details of the subclass.

'Downcasting' is useful when we want to access the specific methods and fields of a subclass that are not present in the superclass. It allows us to take advantage of the additional functionality provided by the subclass.

Overall, 'upcasting' and 'downcasting' provide flexibility and polymorphism in Java.

Back to Top ↑

Follow up 3: What happens if downcasting is not done properly?

Answer:

If downcasting is not done properly, it can result in a 'ClassCastException' at runtime. This occurs when we try to cast an object to a subclass type that is not compatible with its actual type.

For example, let's say we have a class hierarchy where 'Cat' is a subclass of 'Animal'. If we try to downcast an 'Animal' object to a 'Cat' object, but the actual object is not an instance of 'Cat', a 'ClassCastException' will be thrown.

To avoid this, it is recommended to use the 'instanceof' operator to check the compatibility of types before performing downcasting.

Back to Top ↑