The tricky case of type generators in Java

I would like to have a type in Java that references itself in a specific way.

To be precise, I want to have a command class that 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 send to the device and produce a result of a certain type.

Now I want to override mine GenericCommand<T>

so that it implements a special type of command, perhaps FooCommand

that creates Double

:

public class QueryValueCommand extends GenericCommand<Double> {
}

      


Now I am instantiating this class and want it to accept GenericCommandListener<QueryValueCommand>

. But I cannot do this; all I can do is accept GenericCommandListener<GenericCommand<Double>>

.

I see the following ways:

  • Do something with ? super

    or ? extends

    in the definition of class listeners GenericCommand

    . I tried several combinations but didn't work as either the object can't be put into the list or the call doesn't work.

  • Change the definition of the Listener class, but how?

  • Define the class in a GenericCommand

    different way so that it always uses exactly the correct type of listener references:

    public abstract class GenericCommand<T> implements Future<T> {
        private final List<GenericCommandListener<MyExactTypeEvenIfSubclassing>> listeners = ...;
    }
    
          

    so what is derived from it QueryValueCommand

    takes on a value GenericCommandListener<QueryValueCommand>

    ?

+3


source to share


2 answers


As suggested by aruisdante, the class GenericCommand

should be like this:

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 should also change like this:

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);

      

+2


source


If you implement GenericCommandListener

like this:

  public interface GenericCommandListener<T> {
    public <U extends GenericCommand<T>> void onValueAvailable(U theCmd);
  }

      

Then you can add listeners to your class GenericCommand

like this:



  public abstract class GenericCommand<T> implements Future<T> {
    private final List<GenericCommandListener<T>> list = new ArrayList<>();

    public <U extends GenericCommandListener<T>> void addListener(U listener) {
      list.add(listener);
    }

      

Does it help?

0


source







All Articles