我得到了一个编译错误,我不明白原因。
我正在尝试创建一个扩展另一个生成器的生成器,所有这些生成器都使用泛型类型。
问题是一些泛型方法的返回类型是父类,而不是子类,这就阻止了我链接任何子方法。
下面是一个简单的例子:
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");
}
}
为什么会出现编译错误?我怎样才能使它按预期工作?
编辑:
由于下面的答案,我通过以下两个更改成功地解决了这个问题
1-我将BuilderChildStatic类generic更改为正常的有界泛型类型,而没有(奇怪的重复出现的泛型模式)内容,
因此,它将如下所示:
public static class BuilderChildStatic<B extends BuilderChildStatic> extends BuilderParent.BuilderParentStatic<BuilderChildStatic<B>> {
2-另一个变化是我在main方法中的声明中避免了原始类型,因为现在我可以在声明时指定类型
BuilderChild.BuilderChildStatic<BuilderChild.BuilderChildStatic> builder = new BuilderChild.BuilderChildStatic<>();
除了这两点之外,问题中的其他内容都保持不变
这样它就像我预期的那样。
感谢伟大的答案和解释
Philip Voronov的解释是正确的(我赞成),但是既然你也要求解释如何修复它 . . . 最简单的修复方法是将每个构建器类一分为二:
BuilderChiltStatic
和BuilderChildStatic
完全相同(但可能重命名),以实现链接/继承/等。例如,如果您将BuilderChildStatic
和BuilderChildStatic
重命名为BuilderChiltGeneric
和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
。
这样,您可以避免原始类型(以及它们带来的所有问题),但无需到处指定类型参数。
您使用原始类型,因此在第一种情况下builder。withChildStuff(“childStuff”)
返回BuilderChildStatic
(从类型参数边界)的值,该值具有父方法和父ID
;在第二种情况下,builder。withParentId(1)
返回BuilderParentStatic
的值,因此该值没有子方法。
这个答案适用于原始问题,而不是没有重复通用边界的更新问题。
使用原始类型会导致问题。您可以通过添加通用通配符约束来“修复”,即:
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类型。
此代码在Java 8中编译,但在Java 7中编译失败: 它不能推断从映射返回的映射的具体类型。空(): 如果将调用更改为f(Map),则会编译。 但是如果您将调用更改为f(Map.empty())。放(1,“A”)。put(2,“B”)) ,它无法在Java 7和8上再次编译。为什么?
我使用的是Java8。 我最近遇到了这个问题: 这不会抛出java.lang.ClassCastException,为什么呢? 我总是想<code>和<code>System.out。println调用。但当我尝试这样做时,它会像预期的那样抛出异常。
编译时,此代码将产生以下+错误: 问题是访问中的类型T与列表中的T不相同。如何修复此编译问题?
问题内容: 没有静态成员可以使用类型参数,但是可以使用泛型类型参数调用静态成员吗?例如:- 这里的add()是一个静态方法。 在类似的主题上也有一些C#问题和答案,但是我不太确定如何在Java中使用它。 问题答案: 不,如果A是泛型类型,则无法执行。(Bozho对fast的回答是:),可能认为A是具体类型。 可行的方法如下。 但这可能不是您想要的。 阅读您的评论后,听起来您真正想要做的是: 您
我一直在尝试泛型,很快我就遇到了一些我无法解释的事情 例如: 我不明白
问题内容: 如果在Java中创建泛型类(该类具有泛型类型参数),则可以使用泛型方法(该方法带有泛型类型参数)吗? 考虑以下示例: 正如您对通用方法所期望的那样,我可以使用任何对象调用的实例: 但是,如果我尝试使用 不 指定泛型类型的实例,则无论传入什么,我都会调用返回, 奇怪的是,如果返回类型是通用类,它将编译(例如(实际上,这可以解释-参见下面的答案)): 此外,如果输入通用类,即使仅使用通配符