JavaFX Properties
JavaFX Properties
If you have built any Swing or raw-AWT application you know the frustration: you update a field in your model, then manually call label.setText(...), repaint, and hope you did not miss any path. JavaFX solves this at the language level with a property system — a set of observable wrappers around ordinary Java values. When the value changes, every interested party is notified automatically. This lesson covers what properties are, how they work under the hood, and the idiomatic way to write a model class that uses them.
What Is an Observable Property?
A JavaFX property is an object that wraps a value and provides three capabilities:
- Read/write access to the underlying value (
get()/set()). - Change notification — listeners registered on the property are called whenever the value changes.
- Binding support — the property can be linked to another property so they stay in sync without manual synchronisation code.
JavaFX ships concrete implementations for every primitive type and for Object:
StringProperty/SimpleStringPropertyIntegerProperty/SimpleIntegerPropertyDoubleProperty/SimpleDoublePropertyBooleanProperty/SimpleBooleanPropertyObjectProperty<T>/SimpleObjectProperty<T>
The naming pattern is consistent: the interface (StringProperty) describes the contract; the implementation (SimpleStringProperty) is what you instantiate in your own model classes.
The JavaFX Property Hierarchy
The full type hierarchy is worth understanding so you can read JavaFX API documentation without confusion:
Observable— base interface; can fire invalidation events.ObservableValue<T>— addsgetValue()and change listeners.ReadOnlyProperty<T>— addsgetBean()andgetName()(metadata about the owning object and field name).Property<T>— addssetValue()and binding methods.WritableValue<T>— addssetValue()independently.
Specialised interfaces like StringProperty extend both Property<String> and WritableStringValue, adding type-specific get()/set(String) that avoid boxing.
Writing a Model Class with Properties
The JavaFX convention for a model class (often called a JavaFX Bean) mirrors the Java Beans convention but adds a third accessor — the property accessor — which returns the property object itself so callers can bind to it.
The three-argument constructor (new SimpleStringProperty(bean, name, initialValue)) passes metadata: this is the owning object and "name" is the field name. This metadata is optional but valuable when debugging — it appears in property toString() output and in Scene Builder diagnostics.
xxxProperty() accessor. Controllers and bindings use the property accessor; service and persistence code uses the plain getter/setter. Mixing the two audiences through a single accessor leads to tangled, hard-to-test code.
Attaching Change Listeners
Once you have a property object you can register a ChangeListener on it. The listener receives the observable itself, the old value, and the new value:
Notice the lambda signature for IntegerProperty: even though the underlying value is int, the listener receives Number (the boxed super-type). Call .intValue() to unbox.
Read-Only Properties
Sometimes you want a property that is publicly readable but only writable from inside the class — for example, a computed value like a total price. JavaFX provides ReadOnlyIntegerWrapper (and the equivalent for other types) for this pattern:
The wrapper holds the real IntegerProperty. getReadOnlyProperty() returns a view that shares the same value but exposes no set() method. Callers can bind to it and listen for changes but cannot modify it.
xxxProperty() accessor returns the ReadOnlyIntegerWrapper instead of calling getReadOnlyProperty(), external code can cast it back to a writable IntegerProperty and break your encapsulation. Always return the read-only view from the public accessor.
Properties on the JavaFX UI Thread
All JavaFX scene-graph mutations — including writes to properties that are bound to UI nodes — must happen on the JavaFX Application Thread. If you update a property from a background thread (say, after a network call) you must marshal the update:
Platform.runLater() queues the Runnable onto the JavaFX pulse queue. For heavier background work, the next lesson introduces Task and Service which handle this automatically.
Summary
JavaFX properties are observable wrappers that decouple the producer of a value from every consumer that cares about it. The three-accessor Bean pattern — plain getter, plain setter, and a xxxProperty() method — is the standard contract your model classes should follow. In the next lesson you will see how to connect two properties together with binding, eliminating the change-listener boilerplate entirely for the most common synchronisation needs.