Java 为什么对泛型子类型进行强制转换会产生警告?

Java 为什么对泛型子类型进行强制转换会产生警告?,java,Java,我正在尝试对一个生成器类进行子类化,如中所述 这里给出的解决方案非常简单。下面是基类: public class NutritionFacts { private final int calories; public static class Builder<T extends Builder> { private int calories = 0; public Builder() {} public T c

我正在尝试对一个生成器类进行子类化,如中所述

这里给出的解决方案非常简单。下面是基类:

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;
    }
}
公共类营养品事实{
个人最终热量;
公共静态类生成器{
私人int卡路里=0;
公共生成器(){}
公共热量(int val){
卡路里=val;
返回(T)这个;
}
public NutritionFacts build(){返回新的NutritionFacts(this);}
}
受保护的营养成分(建筑商){
卡路里=卡路里;
}
}
和子类:

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;
    }
}
公共类GMOFacts扩展了NutritionFacts{
私有最终布尔值;
公共静态类生成器扩展了NutritionFacts.Builder{
私有布尔hasgom=false;
公共生成器(){}
公共建筑商GMO(布尔值){
hasgom=val;
归还这个;
}
public GMOFacts build(){返回新的GMOFacts(this);}
}
受保护的GMOFacts(建筑商){
超级建筑商;
hasgom=builder.hasgom;
}
}
然而,
返回(T)这个
NutritionFacts.Builder#carries(int)
中会导致

NutritionFacts.java使用未经检查或不安全的操作

警告

考虑到泛型,为什么这个cast不安全?我知道
T扩展了Builder
,而
this
Builder
,那么为什么从
this
Builder
)到
T
扩展了Builder
)的转换不安全呢?演员应该永远不会失败,对吗

说你有

Builder<SubClassOfBuilder> b = ...
SubClassOfBuilder scob = b.calories(1); // compiles fine.
Builder b=。。。
子类生成器scob=b.卡路里(1);//汇编得很好。

问题是
b
可能不是
子类生成器
,因此您将在运行时得到一个ClassCastException。

它很可能会失败。在

public T calories(int val) {
    calories = val;
    return (T) this;
}
假设
T
in

public static class Builder<T extends Builder> {
公共静态类生成器{
将始终绑定到子类的类型。例如

public static class Real extends Builder<Real>{}
公共静态类Real扩展生成器{}
Java中没有办法强制类型参数与声明的类型本身相同

public static class Fake extends Builder<Real> {}
公共静态类假扩展生成器{}
那么

Builder<Real> fake = new Fake();
Real real = fake.calories(4);
Builder-fake=new-fake();
真=假。卡路里(4);
将失败,出现
ClassCastException


如果您知道这种情况永远不会发生,请忽略警告。强制转换是一种明确的断言,表明您知道自己在做什么。

因为NutritionFacts.Builder是原始类型。如果要避免编译器警告,应参数化对泛型类型NutritionFacts.Builder的引用

你真的应该这样做:

public static class Builder<T extends Builder<?>>

publicstaticclassbuilder仅仅因为
this
Builder
T
Builder
的子类型,并不意味着
this
T


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

但我没有一个
Builder
?我有一个
gmofats.Builder
谢谢:这是关键的一句话:“在Java中,没有办法强制类型参数与声明的类型本身相同。”,当然,这些例子说明了这一点。从设计角度来看,有什么方法可以补救这种情况吗?@dimadima这是一个好问题。你似乎找到了当前的解决方案。我想,你想要的是。Java没有一个干净的解决方案afaik.Brilliant。那里的链接非常棒。