Memra

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:

  1. Class.forName(name) loads the class named by the string and returns its Class object. If no such class exists, it throws ClassNotFoundException.
  2. getConstructor(long.class) looks up the *public* constructor whose parameter list is exactly (long). Note the primitive class literal long.classLong.class would not match a long parameter. If there is no matching public constructor it throws NoSuchMethodException.
  3. ctor.newInstance(time) actually calls that constructor with the argument time, returning a new Object, which we cast to Event. (The cast can throw ClassCastException at runtime if the named class is not an Event.)

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.

NORMAL ~/memra/learn/comp-308/reflection-constructor-method-field utf-8 LF