0

I have this generic interface:

public interface TjbListener<T> {
    public void hearChange(T t);
}

Which I use like this:

public interface ObjectOneListener extends TjbListener<ClassOne> {

}

I would like to write an abstract generic class A which takes a generic type U as a parameter and has a method (1) which itself calls a method (2) on U. Below is my attempt U should extend (or implement maybe?) the generic TjbListener interface.

public abstract class ListenerInformer<U extends TjbListener<"what should I write here">> {
    List<U> mListeners = new ArrayList<U>();

    public void addListener(U u){
        mListeners.add(u);
    }

    public void informAll("what should I write here"){
        for(U u:mListeners){
            u.hearChange("what should I write here");
        }
    }
}

One solution I thought of as I was writing this question is below, but I don't know if it's really a solution, or if it has subtle problems I don't understand:

public abstract class ListenerInformer<U extends TjbListener<T>,T> {
    List<U> mListeners = new ArrayList<U>();

    public void addListener(U u){
        mListeners.add(u);
    }

    public void informAll(T t){
        for(U u:mListeners){
            u.hearChange(t);
        }
    }
}

UPDATE: BEWARE

I have just discovered that this approach is almost useless for my particular case because the same class cannot implement the same interface with different parameters. See the question linked below. This means that I cannot have one class be a listener of two different types with my (or Johanna's) solution, without using a different strategy like composition.

How to make a Java class that implements one interface with two generic types?

Community
  • 1
  • 1
tjb
  • 11,480
  • 9
  • 70
  • 91
  • I wonder, what problem are you trying to solve? It looks little over-engineered... – aviad Apr 27 '12 at 06:03
  • I second, your solution is nice and I disagree with @aviad, it's not over engeenered. – Snicolas Apr 27 '12 at 06:05
  • @avid the problem I am trying to solve is that I have many obects listening to many other objects. But when those objects are "informed" they are being passed different data (instances of T). I have a solution now that relies on many specific interfaces for each type of Listener, but since the behavior between listeners is the same I would like to make it generic – tjb Apr 27 '12 at 08:13

1 Answers1

3

Your second example should work. But if it is as simple as that, then there is no need for the Generic U, because every instance of a subclass of TjbListener also is an instance of TjbListener.

You can do more simple:

public abstract class ListenerInformer<T> {
    List<TjbListener<T>> mListeners = new ArrayList<TjbListener<T>>();

    public void addListener(TjbListener<T> u){
        mListeners.add(u);
    }

    public void informAll(T t){
        for(TjbListener<T> u:mListeners){
            u.hearChange(t);
        }
    }
}

That works as your code does and is easier to handle.

Two generic types is necessary if you need the final implementation type of the subclass of TjbListener as return value of parameter, for example if you have

 public U informAll2(T t){
    for(U u:mListeners){
        u.hearChange(t);
        if (...)
            return u;
    }
}

In this case your declaration with two generic types is correct (just I'm not sure if it is possible to declare the generic U, which depends of T, before you declare T, of if you have to declare T first, like public abstract class ListenerInformer<T, U extends TjbListener<T>> )

Johanna
  • 5,223
  • 1
  • 21
  • 38
  • for my case this really does work, because I'm not returning anything. Thank you for the insightful explanantion – tjb Apr 27 '12 at 08:22
  • oops, sorry, there is another problem with your solution that I didn't see before: the parameter input to addListener is not type checked. The value of T must already be specified in the TjbListener Interface as the input parameter of hearChange, which is not correct. – tjb Apr 27 '12 at 08:30
  • Yes, you're right. I forgot to parameterize the TjbListener. I added the missing ``. Now it should be better. – Johanna Apr 27 '12 at 08:44
  • I see, however I have just discovered that what I'm trying to do fails at a more basic level. – tjb Apr 27 '12 at 08:45