I find the generics whose generics params extends itself(here). I don't understand that well.I suspect that it is wrong at the beginning, but no one put forward. I have some questions about this:
here is the generics style code which is picked from (here).
abstract class Base<T extends Base<T>> {
}
class Variant<T extends Variant<T>> extends Base<T> {
}
Thanks!
I think you're talking about F-bounded types. I've found them very useful in situations where two hierarchies are directly correlated. The most clear case that comes to mind is the builder pattern, targeted to a hierarchy of classes. In this case, it could be of use to have a hierarchy of builders as well.
An example might shed some light. Consider the following (very stereotyped) hierarchy:
public abstract class Human {
protected String name;
protected int age;
}
public class Woman extends Human {
protected String loveMovie;
}
public class Man extends Human {
protected String soccerTeam;
}
Now, we want to create builders for Man
and Woman
. We could implement a builder for each one, duplicating the methods to set name
and age
attributes. However, as Man
and Woman
inherit from Human
, we could have an abstract HumanBuilder
, and make our WomanBuilder
and ManBuilder
inherit from it. This is where F-bounded types come in handy.
The Human
class, along with its HumanBuilder
, would be as follows:
public abstract class Human {
protected String name;
protected int age;
public static abstract class HumanBuilder<H extends Human,
T extends HumanBuilder<H, T>> {
protected String name;
protected int age;
@SuppressWarnings("unchecked")
public T name(String name) {
this.name = name;
return (T) this;
}
@SuppressWarnings("unchecked")
public T age(int age) {
this.age = age;
return (T) this;
}
protected void fill(H human) {
human.name = this.name;
human.age = this.age;
}
protected abstract H create();
public final H build() {
H human = this.create();
this.fill(human);
return human;
}
}
}
This would be the Woman
class, along with its WomanBuilder
:
public class Woman extends Human {
protected String loveMovie;
public static class WomanBuilder extends HumanBuilder<Woman, WomanBuilder> {
protected String loveMovie;
public WomanBuilder loveMovie(String loveMovie) {
this.loveMovie = loveMovie;
return this;
}
@Override
protected void fill(Woman woman) {
super.fill(woman);
woman.loveMovie = this.loveMovie;
}
@Override
protected Woman create() {
return new Woman();
}
}
}
And finally, here's the Man
class, along with its ManBuilder
:
public class Man extends Human {
protected String soccerTeam;
public static class ManBuilder extends HumanBuilder<Man, ManBuilder> {
protected String soccerTeam;
public ManBuilder soccerTeam(String soccerTeam) {
this.soccerTeam = soccerTeam;
return this;
}
@Override
protected void fill(Man man) {
super.fill(man);
man.soccerTeam = this.soccerTeam;
}
@Override
protected Man create() {
return new Man();
}
}
}
This approach saves quite a lot of lines of code, especially in a real-world use case.
As expected, using the builders does not require any casting:
Man man = new Man.ManBuilder()
.name("Joe")
.age(29)
.soccerTeam("Los Angeles Galaxy")
.build();
Woman woman = new Woman.WomanBuilder()
.name("Jane")
.age(25)
.loveMovie("Meet Joe Black")
.build();
From the code you linked, it looks like the Base and Variant classes hold methods that return references to an object of their own class, I'm guessing similar to a Singleton.
abstract class Base {
protected abstract Base getNewInstance();
}
Now if you wanted to return an instance of a subclass of Base, you'd be out of luck. That's where generics come in.
class Variant<T extends Variant<T>> extends Base<T> {
protected Base<T> getNewInstance() {
return new Variant();
}
}
In regards to usefulness, I personally don't really see any. It's unnecessarily complicated and could probably be refactored to something much more readable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With