Polymorphism in Java - Duck Typing

2 minute read

Polymorphism is a core concept in object-oriented programming (OOP) that allows objects of different types to be treated as objects of a common superclass. It enables flexibility and code reusability by providing a way to write code that operates on objects without needing to know their specific type. In this tutorial, we’ll explore polymorphism in Java, focusing on a concept called “Duck Typing,” its implementation, and provide examples to illustrate its usage.

Understanding Polymorphism

Polymorphism allows objects of different types to be treated uniformly based on their common superclass. It enables the same code to be used with different types of objects, promoting code reuse and flexibility. Polymorphism is achieved through method overriding, where a subclass provides a specific implementation of a method defined in its superclass.

Duck Typing in Java

Duck typing is a concept borrowed from dynamically typed languages like Python. In Java, while the language itself does not support duck typing in its traditional sense, the principles of duck typing can still be applied through polymorphism. The idea is that if an object behaves like a duck (i.e., it quacks like a duck and swims like a duck), then it can be treated as a duck, regardless of its actual type.

Example Illustration of Duck Typing

Let’s illustrate duck typing in Java with an example:

// Interface representing a Duck
interface Duck {
    void quack();
    void swim();

// Class representing a Mallard Duck
class MallardDuck implements Duck {
    public void quack() {
        System.out.println("Quack Quack!");

    public void swim() {
        System.out.println("Swimming gracefully.");

// Class representing a Rubber Duck
class RubberDuck implements Duck {
    public void quack() {
        System.out.println("Squeak Squeak!");

    public void swim() {
        System.out.println("Just floating on water.");

// Class representing a Dog (not a Duck)
class Dog {
    public void bark() {
        System.out.println("Woof Woof!");

// Main class
public class Main {
    // Method to perform actions on a Duck
    public static void performDuckActions(Duck duck) {

    public static void main(String[] args) {
        Duck mallardDuck = new MallardDuck();
        Duck rubberDuck = new RubberDuck();
        Dog dog = new Dog();

        // Both Mallard Duck and Rubber Duck can be treated as Ducks
        performDuckActions(mallardDuck); // Output: Quack Quack! \n Swimming gracefully.
        performDuckActions(rubberDuck);  // Output: Squeak Squeak! \n Just floating on water.

        // Dog cannot be treated as a Duck
        // performDuckActions(dog); // Compilation error: incompatible types

In this example:

  • We have an interface Duck representing the behavior of a duck with methods quack() and swim().
  • Classes MallardDuck and RubberDuck implement the Duck interface, providing specific implementations for the methods.
  • We have a class Dog that does not implement the Duck interface.
  • The performDuckActions() method demonstrates duck typing by accepting any object that implements the Duck interface and treating it as a duck.

Benefits of Duck Typing in Java

  1. Flexibility: Duck typing allows for more flexible and dynamic code, as objects can be treated based on their behavior rather than their specific type.
  2. Code Reusability: Duck typing promotes code reusability by enabling the same code to be used with different types of objects that exhibit similar behavior.
  3. Simplicity: Duck typing simplifies code by focusing on the common behavior of objects rather than their specific implementations, leading to cleaner and more maintainable code.


In conclusion, while Java does not directly support duck typing, the principles of duck typing can still be applied through polymorphism. By treating objects based on their behavior rather than their specific type, developers can write more flexible, reusable, and expressive code in Java, promoting code quality and maintainability.