tags:

views:

220

answers:

3

I have been struggling for some time trying to define a generic interface, but I fail to achieve what I want. The following is a simplified example of the problem.

Let's say I have a generic Message class

public class Message<T> {

    private T content;

    public void setContent(T content) {
     this.content = content;
    }

    public T getContent() {
     return content;
    }

}

and then I want to define an interface for transfering things:

public interface Transfer<Message<T>> {

    public void send(Message message);

}

The problem is that the compiler does not accept this, and always complains about the second '<' character, no matter what variations I try. How do I specify this interface so that it is bound to a generic type (based on Message) and also have access to the parameterized type?

My plan was to use this interface like the following:

public class Carrier<Message<T>> implements Transfer<Message<T>> {

    public void send(Message message) {
     T content = message.getContent();
     print(content);
    }

    public static void print(String s) {
     System.out.println("The string equals '" + s + "'");
    }

    public static void print(Integer i) {
     System.out.println("The integer equals " + i);
    }

    public static void main(String[] args) {
     Carrier<Message<String>> stringCarrier = new Carrier<Message<String>>();
     Message<String> stringMessage = new Message<String>("test");
     stringCarrier.send(stringMessage);

     Carrier<Message<Integer>> integerCarrier = new Carrier<Message<Integer>>();
     Message<Integer> integerMessage = new Message<Integer>(123);
     integerCarrier.send(integerMessage);
    }
}

I have done some searching and reading (among other things Angelika's generics faq), but I am not able to tell if this is not possible or if I am doing it wrong.

Update 2009-01-16: Removed the original usage of "Thing" instead of "Message< T >" (which was used because with that I was able to compile without getting syntax errors on the interface).

+5  A: 

It looks to me like you want:

public class Carrier<Thing extends Message<Foo>, Foo>
    implements Transfer<Thing>

That way the compiler will know that thing is a Message<Foo> and will therefore have a getContent() method.

You'll need to use it as:

Carrier<Message<String>, String>

But you've currently got a bit of a disconnect. You're implementing Transfer<Thing> but you're trying to use thing as if it's a Message<Thing> look at your send method - you're calling it with a String and an Integer. Those classes don't have getContent() methods.

I suspect you should actually be implementing Transfer<Message<Thing>> instead of Transfer<Thing>

Jon Skeet
Yes, bingo! I want to define the interface as "Transfer<Message<Thing>>" and that was my first approach. However, when I try that the compiler always gives syntax error on the second < no matter what variant of that I try. So using just "Transfer<Thing>" was the only way I got something to compile.
hlovdal
So why haven't you accepted this answer then?
Allain Lalonde
A: 

Regardless of how you solve your generics problem, your code will not compile because you do not have a print method that takes a type of T as a parameter.

I believe you will have to do instance of checks if you want the functionality you are looking for. So, I don't think you gain any value from the generic type in this case.

A: 

You only need to specify T for the class, and then use Message< T > for your argument/return types.

public interface Transfer<T> {
    public void send(Message<T> message);
}

The reason you don't use Message< T > is because you're providing the 'this is a message' context in your arguments and return types.

Strilanc