Java polymorphism through injection at runtime

321 views Asked by At

I hear that in Java I can achieve polymorphism through injection at runtime. Can someone please show a simple example of how that is done? I search online but I can't find anything: maybe I am searching wrong. So I know about polymorphism through interface and and extension such as

class MyClass extends Parent implements Naming

in such case I am achieving polymorphism twice: MyClass is at once of type Parent and Naming. But I don't get how injection works. The idea is that I would not be using the @Override keyword during injection. I hope the question is clear. Thanks.

So the end result here, per my understanding, is to change the behavior of a method through injection instead of by @Override it during development.

2

There are 2 answers

0
Chetan Kinger On BEST ANSWER

So I know about polymorphism through interface and and extension such as

class MyClass extends Parent implements Naming

This is known as inhertiance and not polymorphism. MyClassis a Parent and MyClass is also a Naming. That being said, inheritance allows you to achive polymorphism.

Consider a class other thanMyClass that also implements Naming :

class SomeOtherClass implements Naming {
     @Override
     public void someMethodDefinedInTheInterface() {

     }
 }

Now consider a method that takes a Naming argument somewhere in your code base :

public void doSomething(Naming naming) {
     naming.someMethodDefinedInTheInterface();
}

The doSomething method can be passed an instance of any class that implements Naming. So both the following calls are valid :

doSomething(new MyClass());//1
doSomething(new SomeOtherClass());//2

Observe how you can call doSomething with different parameters. At runtime, the first call will call someMethodDefinedInTheInterface from MyClass and the second call will call someMethodDefinedInTheInterface from SomeOtherClass. This is known as runtime-polymorphism which can be achieved through inheritance.

But I don't get how injection works. The idea is that I would not be using the @Override keyword during injection

That's true in the broader sense. To inject something into a class, the class should ideally favor composition over inheritance. See this answer that does a good job in explaining the reason for favoring composition over inheritance.

To extend the above example from my answer, let's modify the doSomething method as follows :

  public class ClassHasANaming {
      private Naming naming;

      public ClassHasANaming(Naming naming) {
          this.naming = naming;
      }

      public void doSomething() {
           naming.someMethodDefinedInTheInterface();
      }
  }

Observe how ClassHasANaming now has-a Naming dependency that can be injected from the outside world :

ClassHasANaming callMyClass = new ClassHasANaming(new MyClass());
callMyClass.doSomething();

If you use the Factory pattern, you can actually chose which subclass gets instantiated at runtime.

Do you think we could have done what we did above using inheritance?

 public class ClassIsANaming implements Naming {
    public void doSomething() {
        someMethodDefinedInTheInterface();
    }

    @Override
    public void someMethodDefinedInTheInterface() {
        //....
    }
 }

The answer is No. ClassIsANaming is bound to a single implementation of the someMethodDefinedInTheInterface method at compile time itself. `

2
rghome On

Taking a contrived example. You have a class Store that stores things:

class Store {

    private List l

    void store(Object o) {
       l.add(o);
    }

    void setStoreProvider(List l) {
        this.l = l
    }
}

You can inject the actual List used as the backing storage using setStoreProvider which could be a linked list, array backed list, whatever.

Hence, depending on the injected type your Store class would have the features of the injected type (with regards to memory usage, speed, etc).

This is a kind of polymorphism without the class implementing an interface.