top of page
Writer's pictureTravis Martin

Polymorphism OOP examples Java

Updated: Jul 19, 2021

I am writing this to keep example on programming concepts, this will be on polymorphism, both using interface and abstract objects.


Interface base approach

Using an interface to have abstraction is in my opinion easier to understand what is going on since everything is encapsulated within the class implementation. The only thing made public is the interface methods. Unlike the abstract class approach there are no super classes or attributes/methods inherited.

Interface:

interface Animal {
    String makeSound();
}

Class' that implement the interface:

class Cat implements Animal {
    @Override
    public String makeSound() {
        return "Cat Noises";
    }
}
class Dog implements Animal {
    @Override
    public String makeSound() {
        return "Dog Noises";
    }
}

Test class that wires everything together:

import java.util.ArrayList;

class Polymorphism {
    public static void main(final String[] args) {
        // List of objects
        Animal Fluffy = new Cat();
        Animal BigRedDog = new Dog();
        // List of Functionality
        ArrayList<Animal> farmAnimals = new ArrayList<>();
        // Add Objects to arraylist
        farmAnimals.add(Fluffy);
        farmAnimals.add(BigRedDog);

        farmAnimals.forEach((animal -> {
            System.out.println(animal.makeSound());
        }));
    }
}

Output

Cat Noises
Dog Noises

Benefits of using this approach

Helps encapsulate all functionality into each class, this allows one interface with many different implementations.


Abstract Objects and Methods

This one is slightly more complicated, we are now inheriting functionality OR attributes given from parent class. To take it a step further I will add an abstract class that extends an abstract class (double abstraction) this will make sense once I show the problem at hand. Obviously this type solution might not be feasible for most problems but just doing for fun.


Abstract class'

abstract class Node {
    abstract double calculate();
}

abstract class OpNode extends Node {
    Node left;
    Node right;

    abstract double calculate();
}

This example is a Tree with Operation Nodes (Addition, Multiply ...etc) Value Nodes (Numbers, Floats ...etc) Below is an example Tree That I am creating.
















Tree_Example 1.0


ValueNode will represent the numeric values of each node (1, 3, 7...etc)

class ValueNode extends Node {
    double value;
    public ValueNode(double value) {
        this.value = value;
    }
    @Override
    double calculate() {
        return this.value;
    }
}

Operation Nodes responsible for math operations such as: Addition, Subtracting and Multiplying value nodes together.

class AdditionNode extends OpNode {
    AdditionNode(Node n1, Node n2) {
        super();
        this.left = n1;
        this.right = n2;
    }
    double calculate() {
        return left.calculate() + right.calculate();
    }
}
class SubtractionNode extends OpNode {
    SubtractionNode(Node n1, Node n2) {
        super();
        this.left = n1;
        this.right = n2;
    }
    @Override
    double calculate() {
        return this.left.calculate() - this.right.calculate();
    }
}
class MultiplicationNode extends OpNode {
    MultiplicationNode(Node n1, Node n2) {
        super();
        this.left = n1;
        this.right = n2;
    }
    double calculate(){
        return left.calculate() * right.calculate();
    }
}

Lets wire the objects together based off the image above

class polymorphismTest {
    public static void main(String[] args){
        AdditionNode treeExample = new AdditionNode(
                new MultiplicationNode(
                        new ValueNode(7), 
                        new ValueNode(1)),
                new SubtractionNode(
                        new MultiplicationNode(
                                new ValueNode(1), 
                                new ValueNode(3)),
                        new ValueNode(5)
                ));
        System.out.println(treeExample.calculate());
    }
}

Let me explain what is going on here in steps this code is a reflection of the Tree_Example 1.0 above.

Output

5.0

Explanation of maybe confusing code.

  1. The top node is an AdditionNode which takes 2 Parameters with type Node since each class extends Node this we can pass it any of the ValueNode or OpNode.

  2. We pass in two OpNode's (anything that extends OpNode) MultiplicationNode and SubtractionNode, both require nodes as well.

  3. Pass in Two ValueNode's (7, 1) to MultiplicationNode this finishes the left hand side of the tree.

  4. Pass in MultiplicationNode and ValueNode(5) to SubtractionNode.

  5. Finally Pass in two ValueNode's (1, 3) to the bottom MultiplicationNode finishing the entire tree.

Conclusion

One of the main downfalls I have experienced with using polymorphism is it might not always be obvious what class is getting executed at runtime. There also can be tons of subclass' created, which can get cumbersome.


Any typos or bad info? let me know!


Code located at my github profile.

Comments


bottom of page