I’m learning binding in JavaFX. And I’m confused with generic types. Here I have an example:
public static void main(String[] args) {
Bill electricBill = new Bill();
electricBill.amountDueProperty().addListener(new ChangeListener(){
@Override
public void changed(ObservableValue o,Object oldVal, Object newVal)
{
System.out.println("Electric bill has changed!");
}
});
electricBill.setAmountDue(100.00);
}
It works perfectly but I decided to check what will be this line:
electricBill.amountDueProperty().addListener(new ChangeListener(){…});
without raw type. I found that the only variant that works is
electricBill.amountDueProperty().addListener(new ChangeListener<Object>(){
@Override
public void changed(ObservableValue<? extends Object> o, Object oldVal, Object newVal) {…}
});
As I understand all other variants raises compiler error due to wildcard bounds - one extends T, another - needs superclass:
void addListener(ChangeListener<? super T> listener)
ChangeListener::changed(ObservableValue<? extends T> observable, T oldValue, T newValue)
Is there any way to make parameters of changed()
more specific?
Since amountDueProperty()
returns a DoubleProperty
, which implements ObservableValue<Number>
, you can register a ChangeListener<T>
for any T super Number
(i.e T
can be Number
or any superclass of Number
):
electricBill.amountDueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) {
double newBill = newValue.doubleValue();
// ...
}
});
or, of course, using lambda expressions:
electricBill.amountDueProperty().addListener((obs, oldValue, newValue) -> {
// newValue is a Number, by type inference:
double newBill = newValue.doubleValue();
// ...
});