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.
- Declare your own type parameter with the same or more restrictive bounds. This places the burden of choosing the type parameter on the user of this class.
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>
- Pass the same class as what you're defining to satisfy the original bound.
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, e.g.:
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. E.g. 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 e.g. 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.