Edited 2021-02-08 to reflect API changes for Java 11.
There are a number of cases when you may not know exactly what class you will be instantiating and want to be able to dynamically instantiate specific classes based on a configuration file or a condition during runtime.
To do so, you will need to define a parent class, abstract class, or interface for your classes and can then use the following code as a guide.
Given the following class definitions:
An abstract class
package com.ryanchapin.examples;
public abstract class MyAbstractClass {
protected int x;
protected int y;
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public MyAbstractClass() {}
public MyAbstractClass(Integer x, Integer y) {
this.x = x;
this.y = y;
}
public abstract int doSomething();
}
Two concrete implementations
package com.ryanchapin.examples;
public class MyMultiplyingClass extends MyAbstractClass {
public MyMultiplyingClass() {}
public MyMultiplyingClass(Integer x, Integer y) {
super(x, y);
}
@Override
public int doSomething() {
return x * y;
}
}
package com.ryanchapin.examples;
public class MyAddingClass extends MyAbstractClass {
public MyAddingClass() {}
public MyAddingClass(Integer x, Integer y) {
super(x, y);
}
@Override
public int doSomething() {
return x + y;
}
}
A Main class in which we can run the example
package com.ryanchapin.examples;
public class Main {
public static void main(String[] args) {
String myMultiplyingClass = "com.ryanchapin.examples.MyMultiplyingClass";
String myAddingClass = "com.ryanchapin.examples.MyAddingClass";
/*
* Instantiating the class via the no-arg constructor and then using the
* setters to "configure" the instance.
*/
MyAbstractClass noArgConstructorInstance = null;
try {
@SuppressWarnings("unchecked")
Class<MyAbstractClass> instanceClass =
(Class<MyAbstractClass>) Class.forName(myMultiplyingClass);
noArgConstructorInstance = instanceClass
.getDeclaredConstructor()
.newInstance();
} catch(Exception e) {
e.printStackTrace();
}
noArgConstructorInstance.setX(5);
noArgConstructorInstance.setY(2);
System.out.println(noArgConstructorInstance.doSomething());
/*
* Instantiating the class via the constructor that takes the x and y
* parameter values.
*/
MyAbstractClass xyArgConstructorInstance = null;
try {
@SuppressWarnings("unchecked")
Class<MyAbstractClass> instanceClass =
(Class<MyAbstractClass>) Class.forName(myAddingClass);
/*
* Specify the signature of the constructor that we want to invoke
* by passing in the types defined in the target constructor. Then,
* pass in the arguments to the constructor with the newInstance
* method.
*/
xyArgConstructorInstance = instanceClass
.getDeclaredConstructor(Integer.class, Integer.class)
.newInstance(5, 2);
} catch(Exception e) {
e.printStackTrace();
}
System.out.println(xyArgConstructorInstance.doSomething());
}
}
The Main class illustrates two different ways that we can instantiate our class. One, using the no-arg constructor, and another, by using reflection to get a reference to the constructor with the defined arguments.
The Main class assumes that it will be called with the fully qualified class name as the first argument and will use that String to attempt to instantiate a concrete instance of the MyAbstractClass. The abstract class can be either an interface, or a concrete parent class.