[英]How to bind generic type of static nested class from a static factory method?
我正在使用Effective Java中概述的 Builder 模式的变体,我对 Java generics 的行为感到困惑。
考虑以下 class:
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();
但是,当我从另一个 class 使用它时,它定义了一个具有通用资源子类的方法,它甚至无法编译:
public <T extends Resource> Result<T> createResult(T resource) {
return Result.builder(resource.getClass()).build();
}
编译错误是:
类型不匹配:无法从 Result<capture#1-of 转换? 将 Resource> 扩展到 Result<T>
既然 T 和 T2 都扩展了 Resource,为什么它不能确定 Result.Builder.build() 应该返回一个泛型类型 T 的 Result?
我发现的一种解决方法是放弃 static builder() 方法并改用以下方法:
public <T extends Resource> Result<T> createResult(T resource) {
return new Result.Builder<T>().build();
}
似乎应该有一种方法可以使用 static 工厂方法和隐藏的构造函数......我错过了什么吗?
编译错误的原因是由于Object.getClass()
方法。 根据 java 文档:
返回此 Object 的运行时 class。 The returned Class object is the object that is locked by static synchronized methods of the represented class.
实际结果类型为 Class 其中 |X| 是调用 getClass 的表达式的 static 类型的擦除。 例如,此代码片段中不需要强制转换:
数 n = 0;
Class c = n.getClass();
调用时return Result.builder(resource.getClass()).build();
resource.getClass()
将返回Class<? extends Resource>
Class<? extends Resource>
as Resource
是T
的擦除Result.builder(resource.getClass())
方法将返回Builder<? extends Resource>
Builder<? extends Resource>
。Result.builder(resource.getClass()).build()
将返回Result<? extends Resource>
Result<? extends Resource>
。 T
的类型信息在步骤 1 中丢失。因此编译错误显示为返回类型不兼容。 可以进行以下更改来解决该错误。
T
实例而不是Class<T>
作为 state。Class<T>
而不是Class<? extends Resource>
Class<? extends Resource>
为builder
方法。更改的代码片段:
// Caller
// Solution 1
public <T extends Resource> Result<T> createResult(T resource) {
return Result.builder(resource).build();
}
// Solution 2
public <T extends Resource> Result<T> createResult(Class<T> resourceClass) {
return Result.builder(resourceClass).build();
}
public class Result<T extends Resource> {
...
//Solution 1
public static <T2 extends Resource> Builder<T2> builder(T2 instance) {
return new Builder<T2>();
}
// static factory method to get a builder
// Solution 2
public static <T2 extends Resource> Builder<T2> builder(Class<T2> clazz) {
return new Builder<T2>();
}
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.