Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loose coupling with Class.forName()

interface Bank {
    void connect();
}

class SBI implements Bank {
    static{
        System.out.println("Hello from SBI static");
    }   
    public void connect() {
        System.out.println("Connected to SBI");
    }
}

class LooseCouplingTest {
    public static void main(String... args)throws Exception {
        String className = args[0];
        Class.forName(className);
    }
}

The output for the above code appears to be
Hello from SBI static

What should I add to my code and Y to also print the statement
Connected to SBI

In detail explanation is much appreciated

P.S. Noob here

like image 504
Testaccount Avatar asked Apr 14 '13 06:04

Testaccount


2 Answers

You have to create a new instance of the object (using Class#newInstance()), cast it to the type you want (in your scenario SBI), and then call it.

Working code:

public class LooseCouplingTest {
    public static void main(String... args)throws Exception {
        String className = args[0];
        Class<?> clazz = Class.forName(className);
        Object obj = clazz.newInstance();
        SBI mySBI = (SBI) obj;
        mySBI.connect();
    }
}

Explanation:

  • Class.forName("pkg.SBI") gets a reference for pkg.SBI class in the clazz object.
  • As clazz holds a reference to SBI, calling clazz.newInstance(); is the same as calling: new SBI();.
  • After calling clazz.newInstance();, then, the variable obj will receive a SBI instance.
  • As you want to call a SBI method and obj's type is Object (that's the newInstance() method's return type) you have to cast it to SBI and only then call connect().

Using Java's Reflection API:

If you wish to go even further and not even do the cast (this way LooseCouplingTest never needs to import SBI), you can use Java's Reflection API to invoke the connect() method.

Here's the working code for that:

public class LooseCouplingTest {
    public static void main(String... args) throws Exception {
        String className = args[0];
        Class<?> clazz = Class.forName(className);
        Object obj = clazz.newInstance();
        java.lang.reflect.Method connect = clazz.getMethod("connect");
        connect.invoke(obj);
    }
}
like image 187
acdcjunior Avatar answered Nov 03 '22 22:11

acdcjunior


Class.forName() loads the class. and part of loading the class is executing the static initializer block. That's why you see "Hello from SBI static" printed (the static { ... } part is the static initializer block).

To make "Connected to SBI" appear, you have to create an instance of the class and call the connect() method on it:

Class<? extends Bank> bankClass = (Class<? extends Bank>)Class.forName(className);
Bank bank = bankClass.newInstance();
bank.connect();
like image 32
Jesper Avatar answered Nov 03 '22 22:11

Jesper