为了账号安全,请及时绑定邮箱和手机立即绑定

如何从静态工厂方法绑定静态嵌套类的泛型类型?

如何从静态工厂方法绑定静态嵌套类的泛型类型?

弑天下 2023-08-23 11:40:45
我正在使用《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);        }    }}当我有一个 Resource 的具体子类时,这似乎很有效: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<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(); }似乎应该有一种方法可以使用静态工厂方法和隐藏构造函数来做到这一点......我错过了什么吗?
查看完整描述

1 回答

?
慕妹3146593

TA贡献1820条经验 获得超9个赞

编译错误的原因是由于Object.getClass()方法。根据java文档:

返回此对象的运行时类。返回的 Class 对象是由所表示的类的静态同步方法锁定的对象。

实际结果类型是 Class where |X| 是调用 getClass 的表达式的静态类型的擦除。例如,此代码片段中不需要强制转换:

数字 n = 0;
类 c = n.getClass();


打电话时return Result.builder(resource.getClass()).build();

  1. resource.getClass()Class<? extends Resource>将像Resource擦除一样返回T

  2. Result.builder(resource.getClass())方法将返回Builder<? extends Resource>

  3. Result.builder(resource.getClass()).build()会回来的Result<? extends Resource>

的类型信息T在步骤 1 中丢失。因此,编译错误显示为返回类型不兼容。可以进行以下更改来解决该错误。

  1. 更改构建器方法以接受T实例而不是Class<T>评论中的状态。

  2. 将调用者更改为传递Class<T>而不是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>();

  }

  ...

查看完整回答
反对 回复 2023-08-23
  • 1 回答
  • 0 关注
  • 104 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信