我试图理解interface
源代码中的递归apache thrift
定义
public interface TBase<T extends TBase<?, ?>, F extends TFieldIdEnum> extends Comparable<T>, Serializable {
据我所知TBase
是一个包含类型参数T
和F
的界面。
T
的约束条件是它还必须扩展TBase
,其类型参数包含任何类型。
我感到困惑的是什么是终止TBase
说我有
public class TBaseImpl<A, B> implements TBase<A, B>
A
必须是TBase
所以必须有另一个类实现A
public class TBaseImplA<C, D> implements TBase<C, D>
但C
必须是TBase
所以必须有另一个类实现C
这种情况永远存在。
所以我的问题是
TBase
有人能指出我的方向吗?
由于
答案 0 :(得分:4)
所以必须有另一个类实现A
这不一定是真的。使用这种类型的递归边界,在创建子类型时有两种可能的方法来满足约束。
public class TBaseImpl<A extends TBase<A, B>, B extends TFieldIdEnum> implements TBase<A, B>
或更可能
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>
此模式的一个好处是能够限制意图接受同一类的另一个实例的方法的参数,例如:
public void example(T other)
这是(在Java中)Curiously Repeating Template Pattern。
通常,实现/重写方法必须完全匹配参数类型和参数顺序。但是这种模式允许您通过缩小类型参数来缩小类型。例如。在这种情况下TBaseImpl
中的这种方法只需要TBaseImpl
而不是更广泛的T
或TBase
。在这样的课堂上,课堂与自身之间存在关系。
另一个好处是方法链,其中方法返回this
以允许
obj.method1().method2().method3()
通过这种方式,可以声明链接方法返回T
,例如TBase<TBaseImpl>
变量可以调用这些方法,每个方法返回一个TBaseImpl
,可以在其上调用另一个方法。
T method1(); // in TBase
@Override
TBaseImpl method1(); // in TBaseImpl
顺便提一下,如果您尝试声明一个类型变量是枚举的子类型,那么这不是必需的,因为enum
是final
并且无法扩展。在接口中删除F
并让实现类直接使用枚举更简单。