【问题标题】:Java generics type inference failsJava 泛型类型推断失败
【发布时间】:2021-08-13 12:07:24
【问题描述】:

我正在尝试定义一个类,如果推断该类的类型可能是给定类的子类型,但它似乎不适用于默认的 Java 类型推断机制,我不明白为什么。

这里有一些相关的代码来说明情况

public class ObjectChanged<T extends Something> implements TriggeringCondition<T> {

    private final Class<? extends T> type;
    private String featureName = null;

    protected ObjectChanged(Class<? extends T> type) {
        this.type = type;
    }

    public ObjectChanged<T> onFeature(String featureName) {
        this.featureName = featureName;
        return this;
    }

    public static <X extends Something> ObjectChanged<X> objectChanged(Class<? extends X> type) {
        return new ObjectChanged<>(type);
    }
}

假设我有一个名为 FastCar 扩展 Car 的类。我想为 FastCar 构建一个对象更改,但要将其向下转换为 TriggeringCondition&lt;Car&gt;

如果我编写以下代码,它会按预期工作

TriggeringCondition<Car> test() {
   return objectChanged(FastCar.class);
}

但是,如果我调用 onFeature(String) 方法,它就不再编译,并抱怨我的触发条件是 FastCar 类型,它与 Car 不兼容。

如果现在我像这样定义objectChanged 函数

public static <X extends Something, Y extends X> ObjectChanged<X> objectChanged(Class<Y> type, Class<X> baseType) {
    return new ObjectChanged<>(type);
}

然后我可以使用解决问题的代码

TriggeringCondition<Car> test() {
   return objectChanged(FastCar.class, Car.class).onFeature("something");
}

我还发现我可以用这种语法修复以前的构建问题,但它在 imo 中非常难看。

TriggeringCondition<Car> test() {
   return ObjectChanged.<Car> objectChanged(FastCar.class).onFeature("test");
}

有没有办法写出这样的测试方法而不需要额外的参数?

TriggeringCondition<Car> test() {
   return objectChanged(FastCar.class).onFeature("test");
}

【问题讨论】:

    标签: java generics


    【解决方案1】:

    有没有办法写出这样的测试方法而不需要额外的参数?

    没有。

    如果您不想使用类型见证 (&lt;Car&gt;),您所能做的就是将 objectChanged 结果分配给一个变量,然后对该变量调用 onFeature

    TriggeringCondition<Car> test() {
       TriggeringCondition<Car> tc = objectChanged(FastCar.class);
       return tc.onFeature("test");
    }
    

    如果您使用 Guava 的 Immutable*.Builders,这是一个经常出现的问题:

    ImmutableList<String> list =
        ImmutableList.<String>builder()
            .add("foo")
            .build();
    

    这里需要类型见证,否则推断Builder的类型为ImmutableList.Builder&lt;Object&gt;,因为polyexpression的类型是在.add(String)调用之前确定的。

    这很烦人,但这就是野兽的本性。


    您可以做的一件事是定义一个静态upcast 方法:

    static <T extends Something> ObjectChanged<T> upcast(ObjectChanged<? extends T> oc) {
      ObjectChanged<T> result = new ObjectChanged<>(oc.type);
      return result.onFeature("test");
    }
    

    现在你可以调用类似的东西:

    TriggeringCondition<Car> test() {
       return upcast(objectChanged(FastCar.class).onFeature("test"));
    }
    

    【讨论】:

    • 非常感谢安迪的解释!我知道发生了一些奇怪的事情,但无法解释;)也感谢 upcast 方法,将来可能会派上用场!
    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 2015-07-04
    • 1970-01-01
    相关资源
    最近更新 更多