繁体   English   中英

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

[英]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();

  1. resource.getClass()将返回Class<? extends Resource> Class<? extends Resource> as ResourceT的擦除
  2. Result.builder(resource.getClass())方法将返回Builder<? extends Resource> Builder<? extends Resource>
  3. Result.builder(resource.getClass()).build()将返回Result<? extends Resource> Result<? extends Resource>

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

  1. 在您的评论中更改构建器方法以接受T实例而不是Class<T>作为 state。
  2. 将调用者更改为传递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>();
  }
  ...

参考:Object Java Doc , Erasure of Generic Type

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM