Reflection: Constructor, Method & Field
java.lang.reflect lets you build objects from a name string and invoke members discovered at runtime — the Greenhouse event factory.
From the Class object to its members
A Class object is the gateway; the java.lang.reflect package — Constructor, Method, Field — is what you do with it. Reflection means inspecting and using a type's members at runtime, with no compile-time knowledge of which type it is. This is how frameworks build objects whose class names live in a config file, and it is exactly the mechanism the Greenhouse project's Part 2 needs.
The Greenhouse event factory — build an Event by its name
In the control system, every event extends abstract class Event and shares one constructor signature: Event(long delayTime). The subclasses LightOn, WaterOff, Bell, Terminate… all call super(delayTime). An event file contains lines naming events to schedule. The goal is to add a brand-new event type without recompiling the controller — so the controller must turn a *name string* into an object:
import java.lang.reflect.Constructor;
public static Event create(String name, long time) throws Exception {
Class<?> c = Class.forName(name); // e.g. "events.LightOn"
Constructor<?> ctor = c.getConstructor(long.class); // the Event(long) ctor
return (Event) ctor.newInstance(time); // call it -> a live Event
}
Step by step:
Class.forName(name)loads the class named by the string and returns itsClassobject. If no such class exists, it throwsClassNotFoundException.getConstructor(long.class)looks up the *public* constructor whose parameter list is exactly(long). Note the primitive class literallong.class—Long.classwould not match alongparameter. If there is no matching public constructor it throwsNoSuchMethodException.ctor.newInstance(time)actually calls that constructor with the argumenttime, returning a newObject, which we cast toEvent. (The cast can throwClassCastExceptionat runtime if the named class is not anEvent.)
Adding a new event type — say FansOn — now means *writing one class and dropping its name in the file*; the controller code never changes. That decoupling is the whole point of the exam question "how do you add a class without recompiling?".
Invoking a method and reading a field reflectively
import java.lang.reflect.Method;
import java.lang.reflect.Field;
Method m = c.getMethod("action"); // public no-arg method named "action"
m.invoke(obj); // calls obj.action()
Method g = c.getMethod("setRings", int.class);
g.invoke(obj, 5); // calls obj.setRings(5)
Field f = c.getDeclaredField("light"); // any access level, declared on c
f.setAccessible(true); // bypass private access
boolean on = (boolean) f.get(obj); // read the field's value
getMethod / getConstructor see only public members (including inherited ones); the getDeclared* variants see members of *any* access level declared by that class but not inherited ones. To touch a non-public member you must call setAccessible(true) first.