为什么转换为通用子类型会产生警告?

时间:2015-01-30 16:41:01

标签: java

我试图将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 Builderthis Builder,那么为什么从thisBuilder)转换为{ {1}}(T)不安全?演员应该永远不会失败,对吧?

4 个答案:

答案 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)

仅仅因为thisBuilderTBuilder的子类型,并不意味着thisT 1}}。

苏格拉底是一个人。女人是一种人。这并不意味着苏格拉底是一个女人。