Inner classes & the link to the outer object
A non-static inner class holds an implicit link to its enclosing instance and its fields.
A class inside an object
A (non-static) inner class is defined inside another class and is bound to a *specific instance* of that outer class. Its superpower: it can directly read and modify the private fields and methods of the enclosing object, as if it were part of it. This is the mechanism the whole Greenhouse design rests on — each event type is an inner class that quietly flips the greenhouse's own state.
Worked example — GreenhouseControls.LightOn
public class GreenhouseControls extends Controller {
private boolean light = false; // private outer state
public class LightOn extends Event { // inner class
public LightOn(long delayTime) { super(delayTime); }
public void action() {
light = true; // reaches the OUTER field directly
}
public String toString() { return "Light is on"; }
}
}
When LightOn.action() runs, light = true; mutates the light field of the *enclosing* GreenhouseControls object — no getter, no reference passed in. The inner class implicitly carries a hidden link to its outer instance. When that name is ambiguous you can write it explicitly as OuterType.this:
public void action() {
GreenhouseControls.this.light = true; // explicit outer 'this'
}
Creating an inner class needs an outer instance
Because every inner-class object belongs to an outer object, you cannot create one without an enclosing instance. Inside a non-static method of the outer class, the outer this is implicit, so plain new LightOn(2000) works. From outside, you must qualify the new with an outer reference using the special outer.new Inner() syntax — exactly what the project's main does:
GreenhouseControls gc = new GreenhouseControls();
gc.addEvent(gc.new Restart(0, filename)); // outer.new Inner(...)
Read gc.new Restart(...) as "make a Restart that belongs to the gc object." That binding is what lets the new Restart later reach gc's eventsFile and event list.