tags:

views:

156

answers:

4
+2  Q: 

Java generic type

When I have an interface

public interface Foo<T> {
    T someMethod();
}

is there any way to assure that when some class implements this interface then generic type is the same implementig class.

For example:

public class Bar implements Foo<Bar>  {
    Bar someMethod() {
        return new Bar();
    }
}
A: 

I can't submit a simple "No." on this site (body too short), so here goes.

No.

Yoni Roit
+4  A: 

No, you can't refer to the implementing class. The best you could do is:

public interface Foo<T extends Foo<?> > {
    T someMethod();
}

Doing this, you can be sure that someMethod() returns an object that implements Foo.


EDIT:

Even with an interface definition like this:

public interface Foo<T extends Foo<T > > {
    T someMethod();
}

You can define a class Bar2

public class Bar2 implements Foo<Bar2 > {
    @Override
    public Bar2 someMethod() {
        return new Bar2();
    }
}

And then you can define a class Bar that implements Foo but doesn't return Bar but Bar2:

public class Bar implements Foo<Bar2 > {
    @Override
    public Bar2 someMethod() {
        return new Bar2();
    }
}

The original question was if you could prepare against the usage of the interface like Bar did.

And the answer is: No.


EDIT:

Angelika Langer gives a nice explanation of How do I decrypt "Enum<E extends Enum<E>>"?

tangens
Dear downvoters, could you please explain why you downvoted?
tangens
Because you didn't answer the OP's question. The OP's question asked: how can you ensure that with a type `Bar` that implemented `Foo`, it could only implement `Foo<Bar>`, and not `Foo<Object>` (for example). This is possible, and is done with `java.util.Enum`, for example.
Chris Jester-Young
Because you're wrong? The next answer below you shows a link to a pattern, and examples of working recurring templates that ensure the implementing class uses the base class, as opposed to just any old class..
gnarf
Why this get accepted is beyond me. The OP should really clarify his actual question more.
BalusC
I added an example why the answer of @chris-jester-young isn't better than mine.
tangens
You're right, thanks for the counterexample. I'll update my answer. There still is a difference between using `<?>` versus `<T>`, but that is just hair-splitting at this point and doesn't substantially change the character of the answer.
Chris Jester-Young
A: 

This cannot be done because of Type Erasure.

EDIT :

I got down voted, here is more explanation :

public interface Foo<T>;

T from above is available in run time, so it cannot be checked. However, one could custom annotation that could enforce this.

fastcodejava
Yes, I downvoted you. I wasn't talking about runtime type checking---of course that's impossible in Java---but the OP's question wasn't asking about that.
Chris Jester-Young
Good know, thanks.
fastcodejava
+13  A: 

Yes, this can be done (sort of; see below). (In the C++ world, this is called the "Curiously Recurring Template Pattern", but it applies in Java too):

public interface Recur<T extends Recur<T>> {
    // ...
}

(Note the second mention of T. That's an essential part of the CRTP.)

Also, this is how java.util.Enum is defined, so that an enum type called Foo must derive from Enum<Foo>, so it's not an uncommon pattern in Java either.


I'd like to say that the above is the end of the story, but tangens rightly points out in their revision that it's not totally robust, and really not all that different from their answer in character.

There is one difference (that I can think of) between the Recur<T> solution I have, and the Recur<?> solution that tangens has:

public interface Recur<T extends Recur<T>> {
    T foo();
}

class A implements Recur<B> {
    @Override
    public B foo() {
        return new B();
    }
}

class B implements Recur<A> {
    @Override
    public A foo() {
        return new A();
    }
}

With <T>, the above would not compile; with <?>, it would. But that's just splitting hairs; it doesn't change tangens's central point which is that given an already valid Recur implementation, you can make subsequent implementations use the already-valid type, rather than itself. I still say that's worth something, but that's not worth any more of a something than tangens's answer.

In closing, go ahead and upvote tangens's answer too, if you can. (tangens, you should touch your post so I can upvote you too.) They have a very good point, and I'm sorry that I missed it the first time around. Thanks, tangens!

Chris Jester-Young
No, it can't be done. See my answer for an explanation.
tangens