I would like to have a type in Java which references itself, in a certain way.
To be exact, I want to have a command class which can have listeners:
public abstract class GenericCommand<T> implements Future<T> {
// ...
private final List<GenericCommandListener<GenericCommand<T>>> listeners = new ArrayList<>();
@SuppressWarnings("unchecked")
public void addListeners(
GenericCommandListener<GenericCommand<T>>... listeners) {
this.listeners.addAll(Arrays.asList(listeners));
}
private void onValueAvailable() {
for (GenericCommandListener<GenericCommand<T>> listener : listeners) {
listener.onValueAvailable(this);
}
}
}
A GenericCommandListener looks like
public interface GenericCommandListener<T extends GenericCommand<?>> {
public void onValueAvailable(T theCmd);
}
The purpose of such a command is to be sent to a device and to produce a result of a certain type.
Now, I want to be able to override my GenericCommand<T> so that it implements a special kind of command, maybe a FooCommand, which produces a Double:
public class QueryValueCommand extends GenericCommand<Double> {
}
Now, I create an instance of this class and want it to accept a GenericCommandListener<QueryValueCommand>. But I cannot do so; all I can do is to have it accept a GenericCommandListener<GenericCommand<Double>>.
I see the following ways:
Do something with ? super or ? extends in the listeners definition of the GenericCommand class. I tried several combinations, but neither did work, as either the object cannot be put into the list, or the call does not work.
Change the definition of the Listener class - but how?
Define the GenericCommand class in a different way so that it always uses references to listeners of the exactly correct type:
public abstract class GenericCommand<T> implements Future<T> {
private final List<GenericCommandListener<MyExactTypeEvenIfSubclassing>> listeners = ...;
}
so that the QueryValueCommand derived from it accepts a GenericCommandListener<QueryValueCommand>?
As proposed by aruisdante, the class GenericCommand must depends from itself that way :
public abstract class GenericCommand<C extends GenericCommand<C, T>, T> implements Future<T> {
// ...
private final List<GenericCommandListener<C, T>> listeners = new ArrayList<>();
@SuppressWarnings("unchecked")
public void addListeners(
GenericCommandListener<C, T>... listeners) {
this.listeners.addAll(Arrays.asList(listeners));
}
private void onValueAvailable() {
for (GenericCommandListener<C, T> listener : listeners) {
listener.onValueAvailable((C) this);
}
}
}
The listener class must also by modified that way :
interface GenericCommandListener<C extends GenericCommand<C,T>, T> {
public void onValueAvailable(C theCmd);
}
Now, you can declare :
public class QueryValueCommand extends GenericCommand<QueryValueCommand, Double>
and you can write :
QueryValueCommand command = new QueryValueCommand();
GenericCommandListener<QueryValueCommand, Double> listener = ...;
command.addListeners(listener);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With