You can create an object dynamically at runtime using only the name of the class, input as a simple string. This is done using a part of the Java language called reflection.
Reflection allows old code to call new code, without needing to recompile.
If a class has a no-argument constructor, then creating an object from its package-qualified class name (for example, "java.lang.Integer") is usually done using these methods:
- Class.forName
- Class.newInstance
If arguments need to be passed to the constructor, then these alternatives may be used instead:
- Class.getConstructor
- Constructor.newInstance
The most common use of reflection is to instantiate a class whose generic type is known at design-time, but whose specific implementation class is not. See the plugin topic for an example. Other uses of reflection are rather rare, and appear mostly in special-purpose programs.
Example
Interpreter is an interface used by a simple command line application to interpret user input:
import java.util.*; /** * Parse a line of text and return a result. */ public interface Interpreter { /** * @param aLine is non-null. * @param aResult is a non-null, empty List which acts as an "out" * parameter; when returned, aResult must contain a non-null, non-empty * List of items which all have a <code>toString</code> method, to be used * for displaying a result to the user. * * @return true if the user has requested to quit the Interpreter. * @exception IllegalArgumentException if a param does not comply. */ boolean parseInput(String aLine, List<Object> aResult); /** * Return the text to be displayed upon start-up of the Interpreter. */ String getHelloPrompt(); }
The task is to create a concrete implementation of this interface at runtime, using only the name of a class as input. In this example, the user inputs a package-qualified class name directly on the command line. Then, a corresponding Object is created and cast to the expected type (here, Interpreter). The object can then be used in the same way as any other object.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; /** * Sends text back and forth between the command line and an * Interpreter. JDK less than 6. */ public final class Console { /** * Build and launch a specific <code>Interpreter</code>, whose * package-qualified name is passed in on the command line. */ public static void main(String... aArguments) { try { Class theClass = Class.forName(aArguments[0]); Interpreter interpreter = (Interpreter)theClass.newInstance(); Console console = new Console(interpreter); console.run(); } catch (ClassNotFoundException ex){ System.err.println(ex + " Interpreter class must be in class path."); } catch(InstantiationException ex){ System.err.println(ex + " Interpreter class must be concrete."); } catch(IllegalAccessException ex){ System.err.println(ex + " Interpreter class must have a no-arg constructor."); } } public Console(Interpreter aInterpreter) { if (aInterpreter == null) { throw new IllegalArgumentException("Cannot be null."); } fInterpreter = aInterpreter; } /** * Display a prompt, wait for a full line of input, and then parse * the input using an Interpreter. * * Exit when <code>Interpreter.parseInput</code> returns true. */ public void run() { display(fInterpreter.getHelloPrompt()); //pass each line of input to fInterpreter, and display //fInterpreter's result InputStreamReader inputStreamReader = new InputStreamReader(System.in); BufferedReader stdin = new BufferedReader(inputStreamReader); boolean hasRequestedQuit = false; String line = null; List<Object> result = new ArrayList<Object>(); try { while(!hasRequestedQuit){ line = stdin.readLine(); //note that "result" is passed as an "out" parameter hasRequestedQuit = fInterpreter.parseInput(line, result); display(result); result.clear(); } } catch (IOException ex) { System.err.println(ex); } finally { display(fBYE); shutdown(stdin); } } // PRIVATE private static final String fBYE = "Bye."; private Interpreter fInterpreter; /** * Display some text to stdout. * The result of toString() is used. */ private void display(Object aText){ System.out.print(aText.toString()); System.out.flush(); } /** * Display a List of objects as text in stdout, in the order returned * by the iterator of aText. */ private void display(List<Object> aText) { for(Object item : aText){ display(item); } } private void shutdown(Reader aStdin){ try { aStdin.close(); } catch (IOException ex){ System.err.println(ex); } } }