Reputation: 167
I am trying to understand what the following means?
public class Bar<T extends Bar<T>> extends Foo<T> {
//Some code
}
What is the advantage of doing something like this (e.g. use-case?).
Upvotes: 12
Views: 296
Reputation: 15230
This is very similar with the way java.lang.Enum
class is defined:
public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
private final String name;
private final int ordinal;
protected Enum(String name, int ordinal) {
this.name = name; this.ordinal = ordinal;
}
public final String name() { return name; }
public final int ordinal() { return ordinal; }
public String toString() { return name; }
public final int compareTo(E o) {
return ordinal - o.ordinal;
}
}
As the classes defined like this have to be abstract and cannot be instantiated directly, the pattern is useful in constructs similar with the way normal enums are expanded:
// corresponds to
// enum Season { WINTER, SPRING, SUMMER, FALL }
final class Season extends Enum<Season> {
private Season(String name, int ordinal) { super(name,ordinal); }
public static final Season WINTER = new Season("WINTER",0);
public static final Season SPRING = new Season("SPRING",1);
public static final Season SUMMER = new Season("SUMMER",2);
public static final Season FALL = new Season("FALL",3);
private static final Season[] VALUES = { WINTER, SPRING, SUMMER, FALL };
public static Season[] values() { return VALUES.clone(); }
public static Season valueOf(String name) {
for (Season e : VALUES) if (e.name().equals(name)) return e;
throw new IllegalArgumentException();
}
}
Example from book "Java Generics and Collection".
Upvotes: 4
Reputation: 328598
That's a fairly theoretical example, but you could need it in this case:
public class Bar<T extends Bar<T>> extends Foo<T> {
private final T value;
public T getValue() { return value; }
public void method(T param) {
if (param.getValue().equals(someValue)) {
doSomething();
} else {
doSomethingElse();
}
}
}
You would not be able to call param.getValue()
if T were not a Bar
, which it is because T extends Bar<T>
.
Upvotes: 7
Reputation: 19185
The only thing I could tell is <T extends Bar<T>>
using this you tell that T
is now of Type Bar<T>
which means that T
is Bar
so you can access all the methods available to Bar
, other wise if you only do Bar<T>
you will not be able to access it as T
would have been generic then.
What is the Use then ?
You can use this for composition. e.g.
public class CustomList<T extends List<T>> {
T t;
T get(int index) {
//Some custom code here
return t.get(index);
}
}
Your example is bit wrong since there is no real advantage of Telling that T is of Type Bar since you will have always access to Bar class methods inside Bar class
Upvotes: 0
Reputation: 4569
You are basically limiting the kinds of types that Bar
will "deal with" to anything that extends Bar<T>
. In this case, you want to make sure that Bar
is only dealing with extensions of itself - maybe call a method that's private to Bar
. One simple example is that you might use this class to implement a kind of linked list, and iterate over it while doing something that only Bar
can/should do. Let's say you had the following code:
public class Bar<T extends Bar<T>> extends Foo<T> {
private T next;
//Initialize next in constructor or somewhere else
private void doSomethingOnlyBarCanDo(){
//Do it...
}
public void iterate(){
T t = next;
while(t != null){
t.doSomethingOnlyBarCanDo();
t = t.next;
}
}
}
With this kind of a construct, it'd be very easy to iterate over a "chain" of Bar
instances, because each instance would have a reference to the next - recall that T
extends Bar<T>
, so you can refer to it as such.
Upvotes: 3
Reputation: 115328
One typical use case is Wrapper/Decorator pattern. Bar
probably wraps T
that extends Bar
itself. Foo
is just a parametrized class that deals with T
.
public abstract class Foo<T> {
public abstract void foo(T t);
}
public class Bar<T extends Bar<T>> extends Foo<T> {
private T wrapped;
public Bar(T w) {
this.wrapped = w;
}
public abstract void foo(T t) {
// do something
}
}
Upvotes: 2