我收到编译错误,我不明白其原因。
我正在尝试创建一个扩展另一个构建器的构建器,所有构建器都使用泛型类型。
问题是某些泛型方法的返回类型是父类,而不是子类,这会阻止我链接任何子方法。
这是一个简单的例子:
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<>();
除了那两点之外,问题中的其他所有内容都保持不变
这种方式表现得像我预期的那样。
感谢您的答案和解释
答案 0 :(得分:2)
您使用原始类型,因此在第一种情况下builder.withChildStuff("childStuff")
返回BuilderChildStatic
的值(来自类型参数边界),并且此值具有父级&#39;方法withParentId
;在第二种情况下builder.withParentId(1)
返回BuilderParentStatic
的值,因此该值不具有子方法。
答案 1 :(得分:2)
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
,就像您现在正在做的那样。
这样,您可以避免原始类型(以及它们带来的所有问题),但无需在任何地方指定类型参数。
答案 2 :(得分:1)
这个答案适用于原始问题,而不是没有重复通用范围的更新问题。
使用原始类型会导致问题。你可以修复&#34;它通过添加通用通配符约束,即:
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类型。