Reputation: 2517
I came across the following Java code that uses generics and inheritance. I truly do not understand what the following snippet does:
class A<B extends A<B>> {
...
}
What does this code do?
(I got this from DBMaker in MapDB)
Upvotes: 8
Views: 1211
Reputation: 939
This makes it easier when defining method return types such as this:
class A<B extends A<B>> {
public B getMe(){
return (B) this;
}
}
This tells Java compiler that you are in getMe()
method returning a subclass of class A
.
class C extends A<C> {
}
C c = new C();
c.getMe(); //returns C
Upvotes: 1
Reputation: 10082
This tells that A
needs derived definitions to be able to do some work:
public abstract class A<T extends A<T>> {
protected T instance;
T getOne() {
return instance;
}
}
public class B extends A<B> {
public B() {
instance = this;
}
}
public static void test() {
B b = new B();
b.getOne();
}
This is most commonly used in interface definitions, where one wants to explicitly use instances of classes implementing an interface in return types or in arguments and not the interface itself:
public interface TimeSeries<T extends TimeSeries<T>> {
T join(T ts);
}
public class DoubleTimeSeries implements TimeSeries<DoubleTimeSeries> {
@Override
public DoubleTimeSeries join(DoubleTimeSeries ts) {
return null;
}
}
Upvotes: 2
Reputation: 2238
So I did some tests to figure this one out, and here is my test cases to see how one could use such a generic case:
public class A<B extends A<B>> {
int x = 10;
B test;
void printX() {
System.out.println(x);
}
void setB(B b) {
test = b;
}
void printB() {
System.out.println(test);
}
}
public class B extends A<B> {
}
public class Run {
public static void main(String[] args) {
A<B> test = new A<B>();
B myB = new B();
test.printX();
test.setB(myB);
test.printB();
myB.printB();
}
}
I hope the code might be self explanatory. If not leave a comment and I will try and explain what is going on. Look at the last line, myB.printB(), here we will get a null, because B has not yet been set for myB, but only for test. This demonstrates that we can have an infinite recursion into classes of B inside A (and inside B for that matter).
we can say:
myB.test.printB();
This will get an error (null pointer), but shows that we now have access to test in the A class from B, and we can go as deep as we want recursively with as many cases as we like. So the A class kind of functions as a wrapper of infinitely many B classes. Does this make sense?
Upvotes: 1
Reputation: 34900
It is almost clear and the question actually conists in two parts:
1) why B extends A
?
2) why A
inside B extends A<B>
has generic type B
?
Answers for these parts will be:
1) In particular example this class (A
) is builder class (called DBMaker
), so most of its methods return some type, which extends this builder's class type. This explains, why B
should extend A
class.
2) But, actualy, if we will hide for the second part ...extends A<B>
, we will receive just class A<B>
. So A
has type variable of type B
. That is why in ...extends A<B>
A is marked as type A
having type variable B
.
Upvotes: 5