I am trying to understand this recursive interface
definition in apache thrift
source code
public interface TBase<T extends TBase<?, ?>, F extends TFieldIdEnum> extends Comparable<T>, Serializable {
From my understanding TBase
is a interface containing type parameter T
and F
.
T
has the constraint that it also have to be extending TBase
that has type parameter containing any type.
What I am confused about is what is the terminating TBase
Say I have
public class TBaseImpl<A, B> implements TBase<A, B>
A
has to be a TBase
so there must be another class implement A
public class TBaseImplA<C, D> implements TBase<C, D>
but C
have to be a TBase
so there must be another class implement C
This goes on forever.
So my question is
TBase
Can someone point me a direction?
Thanks
so there must be another class implement A
That is not necessarily true. With this type of recursive bounds, there are 2 possible ways to satisfy the constraint when creating a subtype.
public class TBaseImpl<A extends TBase<A, B>, B extends TFieldIdEnum> implements TBase<A, B>
or more likely
public class TBaseImpl<A extends TBaseImpl<A, B>, B extends TFieldIdEnum> implements TBase<A, B>
public class TBaseImpl<B extends TFieldIdEnum> implements TBase<TBaseImpl, B>
A benefit of this pattern is being able to restrict the parameter of a method that is meant to take in another instance of the same class, eg:
public void example(T other)
This is (in Java) the Curiously Repeating Template Pattern .
Normally an implementing/overriding method must match the parameter types and order of parameters exactly. But this pattern allows you to narrow the type by narrowing the type parameter. Eg such a method in TBaseImpl
in this case would only take a TBaseImpl
and not the broader T
or TBase
. In such a class there is a relationship between the class and itself.
Another benefit is method chaining, in which a method returns this
to allow
obj.method1().method2().method3()
In this way, chaining methods can be declared to return T
, so that eg a TBase<TBaseImpl>
variable can call these methods, each returning a TBaseImpl
on which another method can be called.
T method1(); // in TBase
@Override
TBaseImpl method1(); // in TBaseImpl
Incidentally, if you're trying to declare a type variable that is a subtype of an enum, that's not necessary because an enum
is final
and cannot be extended. It would be simpler to remove F
in the interface and have implementing classes use the enum directly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.