Memra

Reflection: Constructor, Method & Field

◈ 7 cards

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.

Class<?>Constructor<?>ObjectClass.forName"events.LightOn"getConstructorlong.classnewInstancetime(Event) casta live Event
Each arrow names what you are holding. Nothing here is checked by the compiler, so each stage has its own runtime failure: ClassNotFoundException, NoSuchMethodException, then ClassCastException on the final cast.
NORMAL ~/memra/learn/comp-308/reflection-constructor-method-field utf-8 LF