[英]Method call chaining with generic types (Curiously Recurring Generic Pattern)
我收到一个我不明白其原因的编译错误。
我正在尝试创建一个扩展了另一个构建器的构建器,全部使用泛型类型。
问题在于某些通用方法的返回类型是父类,而不是子类,这将阻止我链接任何子方法。
这是简单的示例:
public class BuilderParent {
public static class BuilderParentStatic<B extends BuilderParentStatic<B>> {
public BuilderParentStatic() {}
public B withParentId(int rank) { return self(); }
protected B self() { return (B)this; }
}
}
public class BuilderChild extends BuilderParent {
public static class BuilderChildStatic<B extends BuilderChildStatic<B>>
extends BuilderParent.BuilderParentStatic<B> {
public BuilderChildStatic() {}
public B withChildStuff(String s) { return (B)this.self(); }
protected B self() { return (B)this; }
}
}
public class Test {
public static void main(String args[]) {
BuilderChild.BuilderChildStatic builder = new BuilderChild.BuilderChildStatic();
// OK (uses child first, then parent):
builder.withChildStuff("childStuff").withParentId(1);
// compile error (uses parent first, then child):
builder.withParentId(1).withChildStuff("childStuff");
}
}
为什么会出现编译错误? 如何使它按预期工作?
编辑:
我通过使用以下2项更改,通过以下答案设法解决了该问题
1-我将BuilderChildStatic类的泛型更改为没有(好奇重复生成的泛型模式)的普通有界泛型类型,
因此将如下所示:
public static class BuilderChildStatic<B extends BuilderChildStatic> extends BuilderParent.BuilderParentStatic<BuilderChildStatic<B>> {
2-另一个变化是我避免在main方法的声明中使用原始类型,因为现在我可以在声明时指定类型
BuilderChild.BuilderChildStatic<BuilderChild.BuilderChildStatic> builder = new BuilderChild.BuilderChildStatic<>();
问题中除这2点之外的所有其他内容都保持不变
这样,它的表现就如我预期的那样。
感谢您的出色回答和解释
您使用原始类型,因此在第一种情况下, builder.withChildStuff("childStuff")
返回BuilderChildStatic
值(从类型参数范围开始),并且该值具有父方法withParentId
; 在第二种情况下, builder.withParentId(1)
返回BuilderParentStatic
值,因此该值没有子方法。
菲利普·沃罗诺夫(Philip Voronov)的解释是正确的(我对此表示反对),但是由于您还要求提供有关如何解决它的解释。 。 。 最简单的解决方法是将每个构建器类分为两部分:
BuilderParentStatic
和BuilderChildStatic
(但可能已重命名)的方式,以实现链接/继承/等。 例如,如果将BuilderParentStatic
和BuilderChildStatic
分别重命名为BuilderParentGeneric
和BuilderChildGeneric
,则可以编写:
public static final class BuilderParentStatic
extends BuilderParentGeneric<BuilderParentStatic> {
// empty class definition -- everything we need is in BuilderParentGeneric
}
和
public static final class BuilderChilderStatic
extends BuilderChildGeneric<BuilderChilderStatic> {
// empty class definition -- everything we need is in BuilderChildGeneric
}
然后像现在一样声明并初始化builder
。
这样,您可以避免使用原始类型(以及它们带来的所有问题),而无需在任何地方指定类型参数。
此答案适用于原始问题,不适用于没有重复通用界限的更新问题。
使用原始类型会导致问题。 您可以通过添加通用通配符约束来“修复”它,即:
BuilderChild.BuilderChildStatic<?> builder = new BuilderChild.BuilderChildStatic();
builder.withChildStuff("childStuff").withParentId(1); //works since we used child first then parent
builder.withParentId(1).withChildStuff("childStuff"); //now works
这样,您返回的值将为BuilderChildStatic类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.