Java Generics and Inheritance Replication

I came across the following Java code that uses generics and inheritance. I really don't understand what the following snippet does:

class A<B extends A<B>> { ... } 

What does this code do?

(I got this from DBMaker in MapDB )

+7
java generics
source share
4 answers

This is almost clear, and the question actually consists of two parts:

1) why is B extends A ?

2) why does A inside B extends A<B> have a common type B ?

The answers for these parts will be:

1) In particular, this class ( A ) is the builder class (called DBMaker ), so most of its methods return some type that extends this class of the builder class. This explains why B should extend the class A

2) But, really, if we hide for the second part ...extends A<B> , we get only class A<B> . So A has a variable type of type B That's why in ...extends A<B> A is marked as type A with a variable of type B

+4
source share

This suggests that A requires that derived definitions 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 often used in interface definitions, where you need to explicitly use instances of classes that implement the interface in return types or in arguments, and not in 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; } } 
+2
source share

So, I did some tests to figure this out, and here are my test cases to see how you can use this general 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 can be understood. If you do not leave a comment, I will try to explain what is happening. Look at the last line of myB.printB (), here we get zero, because B is not set for myB yet, but only for the test. This demonstrates that we can have infinite recursion into classes B inside A (and inside B for that matter).

can say:

 myB.test.printB(); 

This will lead to an error (null pointer), but it will show that we now have access to the test in class A from B, and we can go as deep as we want recursively, with as many cases as we like. So class A works like a wrapper for an infinite number of classes B. Does that make sense?

+1
source share

This simplifies the determination of return method types:

 class A<B extends A<B>> { public B getMe(){ return (B) this; } } 

This tells the Java compiler that you are in the getMe() method, which returns a subclass of class A

 class C extends A<C> { } C c = new C(); c.getMe(); //returns C 
0
source share

All Articles