Console input
Abstract Factory
Plugin Factory
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 line is non-null. * @param result is a non-null, empty List which acts as an "out" * parameter; when returned, result 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 line, List<Object> result); /** * 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.util.ArrayList; import java.util.List; import java.util.Objects; /** * Sends text back and forth between the command line and an * Interpreter. */ 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... args) { try { //unchecked cast: Class<Interpreter> theClass = (Class<Interpreter>)Class.forName(args[0]); Interpreter interpreter = theClass.getDeclaredConstructor().newInstance(); Console console = new Console(interpreter); console.run(); } catch (Exception ex){ error(ex + " Cannot instantiate Interpreter."); error("Check class name, class path."); } } public Console(Interpreter interpreter) { this.interpreter = Objects.requireNonNull(interpreter); } /** * 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() throws IOException { display(interpreter.getHelloPrompt()); //pass each line of console input to the interpreter, //and display its result try ( InputStreamReader in = new InputStreamReader(System.in); BufferedReader stdin = new BufferedReader(in); ){ boolean hasRequestedQuit = false; try { while(!hasRequestedQuit){ List<Object> result = new ArrayList<Object>(); String line = stdin.readLine(); //interpret the line of input; //note that "result" is passed as an "out" parameter hasRequestedQuit = interpreter.parseInput(line, result); display(result); } } catch (IOException ex) { error(ex); } } finally { display(BYE); } } // PRIVATE private Interpreter interpreter; private static final String BYE = "Bye."; /** * Display some text to stdout. * The result of toString() is used. */ private void display(Object thing){ System.out.println(thing.toString()); } private static void error(Object thing) { System.err.println(thing); } /** * Display a List of objects as text in stdout, in the order returned * by the iterator of aText. */ private void display(List<Object> text) { text.forEach(p -> display(p)); } }