【发布时间】:2019-09-25 04:16:18
【问题描述】:
我正在使用Effective Java 中概述的 Builder 模式的变体,我对 Java 泛型的行为感到困惑。
考虑以下类:
public class Result<T extends Resource> {
//final members
final boolean success;
final T resource;
//private constructor
private Result(Builder<T> builder) {
success = builder.success;
resource = builder.resource;
}
//getters
public boolean isSuccess() {
return success;
}
public T getResource() {
return resource;
}
//static factory method to get a builder
public static <T2 extends Resource> Builder<T2> builder(Class<T2> clazz) {
return new Builder<T2>();
}
//nested Builder class
public static class Builder<T extends Resource> {
boolean success;
T resource;
private Builder() { }
public Builder<T> success(boolean success) {
this.success = success;
return this;
}
public Builder<T> resource(T resource) {
this.resource = resource;
return this;
}
public Result<T> build() {
return new Result<T>(this);
}
}
}
当我有一个具体的资源子类时,这似乎很有效:
Result<Device> result = Result.builder(Device.class).build();
但是,当我从另一个定义了具有 Resource 的通用子类的方法的类中使用它时,它甚至无法编译:
public <T extends Resource> Result<T> createResult(T resource) {
return Result.builder(resource.getClass()).build();
}
编译错误是:
类型不匹配:无法从 Result
扩展到 Result
既然 T 和 T2 都扩展了 Resource,为什么它不能确定 Result.Builder.build() 应该返回一个泛型类型 T 的 Result?
我发现的一种解决方法是放弃静态 builder() 方法并改用类似的方法:
public <T extends Resource> Result<T> createResult(T resource) {
return new Result.Builder<T>().build();
}
似乎应该有一种方法可以使用静态工厂方法和隐藏的构造函数来做到这一点......我错过了什么吗?
【问题讨论】:
-
有趣的是,如果我更新静态
builder()方法以接受 T2 类型的实例(而不仅仅是它的类),它会起作用:public static <T2 extends Resource> Builder<T2> builder(T2 dummy) { return new Builder<T2>(); }但强迫用户通过似乎有点傻一个 T 的虚拟实例只是为了让泛型工作。 -
我建议看一下 Spring Boot 中使用的构建器层次结构,尤其是
HttpSecurity构建器。泛型可能会有点曲折,但确实可以解决您正在查看的问题。