java - 告诉编译器一个 <Object> 等价于它想要的 <?>

标签 java generics java-8 type-conversion wildcard

我有一些对象可以预先生成一些配置,以便它们以后可以更快地处理计算(可能是几次)。我正在尝试对其进行通用化以避免将配置作为 Object 传递并每次类型转换它。

interface IComputable<T> {
    T configure(); // Generate configuration object
    int compute(T conf); // Run the computation based on the pre-generated configuration
    float precision(T conf); // Make the compute() computation finer-grained
    ...
}
class ComputableInfo {
    IComputable<?> computable;
    Object config; // Real type is <?>
    int result;

    ComputableInfo(String id) {
        computable = ComputableFactory.createFrom(id);
        config = computable.configure();
        result = computable.compute(config); // <<<--- The method compute(capture#3-of ?) in the type TestInterface.IComputable<capture#3-of ?> is not applicable for the arguments (Object)
    }
}
我收到编译错误:

The method compute(capture#3-of ?) in the type TestInterface.IComputable<capture#3-of ?> is not applicable for the arguments (Object)


当然,我可以替换int compute(T conf)通过 int compute(Object conf)但我必须明确地将其转换为适当的 T .这不是什么大问题,但它使代码不那么明显。
我也可以制作 ComputableInfo通用的
interface ComputableInfo<T> {
    IComputable<T> computable;
    T config;
    ...
但这会在其他一些地方产生编译问题(主要是“原始类型”警告),我想避免比以前的解决方法更多的问题(使用 Object 而不是 T )。
有没有办法做到这一点?我什至愿意在编译器设置中将此类问题从错误变为警告,或者可能有一个额外的私有(private)方法可以同时返回 configresult在单个对象中?
编辑:如果我制作 ComputableInfo,则添加“进一步的编译问题”通用:我在接口(interface)中有另一个方法(见已编辑),通过 ComputableInfo 调用:
ComputableInfo<?> info = getInfo(id);
info.computable.precision(info.config); // <<<--- (same kind of error)
问题是 ComputableInfo没办法知道T Computable<T> 的类型(或者我不知道),因为它来自一个从配置文件构建它的工厂。

最佳答案

从通配符类型中获取对象并将其传递回同一对象,这是泛型类型系统的一个已知限制。例如,当你有

List<?> list = …
您可能希望将元素从一个索引复制到另一个索引,例如
Object o = list.get(0);
list.set(1, o);
但它不起作用,即使你避免使用不可表示类型的局部变量。换句话说,即使以下内容也无法编译:
list.set(1, list.get(0));
但是您可以通过允许在操作期间捕获类型参数中的通配符类型来添加执行操作的通用辅助方法:
static <T> void copyFromTo(List<T> l, int from, int to) {
    l.set(to, l.get(from));
}
List<?> list = …
copyFromTo(list, 0, 1); // now works

您也可以将此模式应用于您的案例:
class ComputableInfo {
    IComputable<?> computable;
    Object config; // Real type is <?>
    int result;

    ComputableInfo(String id) {
        computable = ComputableFactory.createFrom(id);
        configureAndCompute(computable);
    }

    private <T> void configureAndCompute(IComputable<T> computable) {
        T typedConfig = computable.configure();
        this.config = typedConfig;
        this.result = computable.compute(typedConfig);
    }
}
这有效,不需要制作 ComputableInfo通用的。
如果您需要捕获类型的时间超过单个方法,例如如果要使用创建的 config多次,您可以使用封装:
class ComputableInfo {
    static final class CompState<T> {
        IComputable<T> computable;
        T config;

        CompState(IComputable<T> c) {
            computable = c;
        }
        private void configure() {
            config = computable.configure();
        }
        private int compute() {
            return computable.compute(config);
        }
    }
    CompState<?> state;
    int result;

    ComputableInfo(String id) {
        state = new CompState<>(ComputableFactory.createFrom(id));
        state.configure();
        result = state.compute();
    }
}
这样,您仍然可以避免将类型参数导出给 ComputableInfo 的用户。 .

关于java - 告诉编译器一个 <Object> 等价于它想要的 <?>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63935181/

相关文章:

java - 拉取 Java 8 镜像时出现 Docker 错误 - "failed to register layer"

java - 从 DialogFragment 获取 View

c# - MVC - 通用操作

c# - 通用类型转换失败

java - 在 Java 8 中使用并行流时,我对同一请求得到不同大小的响应。任何人都可以提供有关如何处理此问题的见解吗?

java - 使用 count 和 limit 时如何获取底层流的大小?

Java 计数器已关闭 --- 与我在这里看到的任何东西都不一样

java - 是否有 MySQL 的 Spring Batch 3 升级脚本?

typescript - Duck 在 Typescript 中输入 Promise

java - 计算两个列表之间的重复值时如何短路?