告诉编译器& lt; Object& gt;等于& lt;?& gt;它想要 [英] Tell compiler an <Object> is equivalent to the <?> it wants

查看:62
本文介绍了告诉编译器& lt; Object& gt;等于& lt;?& gt;它想要的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have objects that pre-generate some configuration once so they can process computation later on faster (possibly several times). I'm trying to genericize it to avoid passing the configuration as an Object and casting it each time.

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)
    }
}

我遇到编译错误:

类型为TestInterface.IComputable< capture#3-of?>的方法compute(capture#3-of).不适用于参数(对象)

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.这不是什么大问题,但是它使代码不那么明显.

Of course, I can replace the int compute(T conf) by int compute(Object conf) but I would have to explicitly cast it to the appropriate T. It's not that big a problem, but it makes the code less obvious.

我也可以将ComputableInfo通用化为

interface ComputableInfo<T> {
    IComputable<T> computable;
    T config;
    ...

但这会在其他一些地方引起编译问题(主要是原始类型"警告),我希望避免比以前的解决方法(使用Object代替T)更多的问题.

but that would create compilation problems in some other places (mostly "raw types" warning) that I'd like to avoid more than the previous workaround (using Object instead of T).

有没有办法做到这一点?我什至愿意在编译器设置中将此类问题从错误变为警告,或者可能有一个额外的私有方法,该方法会在单个对象中同时返回configresult?

Is there a way to achieve that? I'm even open to turning such problem from error to warning in the compiler settings, or maybe have an extra private method that would return both config and result in a single object?

将进一步的编译问题"加起来;如果我使ComputableInfo通用:接口中有另一个方法(请参见编辑),该方法通过ComputableInfo调用:

to add up on the "further compilation problems" if I make ComputableInfo generic: I have another method in the interface (see edited) that is called through the ComputableInfo:

ComputableInfo<?> info = getInfo(id);
info.computable.precision(info.config); // <<<--- (same kind of error)

问题是ComputableInfo无法知道Computable<T>T类型(或者我不知道),因为它来自工厂,工厂是从配置文件中构建的.

The problem is that the ComputableInfo has no way to know the T type of Computable<T> (or no way I know), as it comes from a Factory that builds it from a configuration file.

推荐答案

从通配类型获取对象并将其传递回同一对象是通用类型系统的已知限制.例如,当您拥有

Getting an object from a wildcarded type and passing it back to the same object, is a known limitation of the generic type system. E.g., when you have

List<?> list = …

您可能希望将元素从一个索引复制到另一个索引,例如

you might want to copy an element from one index to another like

Object o = list.get(0);
list.set(1, o);

,但是即使您避免使用不可表示类型的局部变量,它也无法正常工作.换句话说,即使以下内容也无法编译:

but it doesn’t work, even when you avoid the local variable of a non-denotable type. In other words, even the following does not compile:

list.set(1, list.get(0));

但是您可以添加一个通用的辅助方法来执行该操作,方法是允许在操作期间捕获类型参数中的通配符类型:

But you can add a generic helper method that does the operation by allowing to capture the wildcard type in a type parameter for the duration of the operation:

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


您也可以将此模式应用于您的案例:


You can apply this pattern to your case as well:

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设为通用.

This works and does not require making ComputableInfo generic.

如果您需要捕获类型的时间长于单个方法,例如如果要多次使用创建的config,则可以使用封装:

If you need to capture the type for longer than a single method, e.g. if you want to use the created config multiple times, you can use encapsulation:

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();
    }
}

这样,您仍然避免将type参数导出到ComputableInfo的用户.

That way, you still avoid exporting the type parameter to users of ComputableInfo.

这篇关于告诉编译器&amp; lt; Object&amp; gt;等于&amp; lt;?&amp; gt;它想要的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆