我试图将Builder类子类化,如Subclassing a Java Builder class中所述。
那里给出的解决方案非常简单。这是基类:
public class NutritionFacts {
private final int calories;
public static class Builder<T extends Builder> {
private int calories = 0;
public Builder() {}
public T calories(int val) {
calories = val;
return (T) this;
}
public NutritionFacts build() { return new NutritionFacts(this); }
}
protected NutritionFacts(Builder builder) {
calories = builder.calories;
}
}
子类:
public class GMOFacts extends NutritionFacts {
private final boolean hasGMO;
public static class Builder extends NutritionFacts.Builder<Builder> {
private boolean hasGMO = false;
public Builder() {}
public Builder GMO(boolean val) {
hasGMO = val;
return this;
}
public GMOFacts build() { return new GMOFacts(this); }
}
protected GMOFacts(Builder builder) {
super(builder);
hasGMO = builder.hasGMO;
}
}
但是,return (T) this;
中的NutritionFacts.Builder#calories(int)
会产生
NutritionFacts.java使用未经检查或不安全的操作
警告。
考虑到泛型,为什么这个不安全?我知道T extends Builder
而this
是Builder
,那么为什么从this
(Builder
)转换为{ {1}}(T
)不安全?演员应该永远不会失败,对吧?
答案 0 :(得分:2)
它很可能会失败。在
public T calories(int val) {
calories = val;
return (T) this;
}
您认为
中的T
public static class Builder<T extends Builder> {
将始终绑定到子类的类型。例如
public static class Real extends Builder<Real>{}
Java中没有办法强制类型参数与声明的类型本身相同。有人很可能
public static class Fake extends Builder<Real> {}
在这种情况下
Builder<Real> fake = new Fake();
Real real = fake.calories(4);
会因ClassCastException
而失败。
如果您知道这种情况永远不会发生,请忽略警告。演员是一个明确的断言,你知道你在做什么。
答案 1 :(得分:0)
说你有
Builder<SubClassOfBuilder> b = ...
SubClassOfBuilder scob = b.calories(1); // compiles fine.
问题是b
可能不是SubClassOfBuilder
,因此您将在运行时获得ClassCastException。
答案 2 :(得分:0)
因为NutritionFacts.Builder是原始类型。如果要避免编译器警告,应参数化对泛型类型NutritionFacts.Builder的引用。
你应该这样做:
public static class Builder<T extends Builder<?>>
答案 3 :(得分:0)
仅仅因为this
是Builder
而T
是Builder
的子类型,并不意味着this
是T
1}}。
苏格拉底是一个人。女人是一种人。这并不意味着苏格拉底是一个女人。