【问题标题】:Odd Type Inference in Dynamically Typed Method动态类型方法中的奇数类型推断
【发布时间】:2018-01-11 08:03:20
【问题描述】:

在处理配置管理器对象时,我想实现一种方法,该方法可以从管理器的内部索引中检索值并将其自动转换为所需的类型,从而无需显式转换。我认为这很容易,使用 Java 在方法头中提供的泛型系统。所以,我这样构建我的方法:

public <T> T getSettingAutocast(String key)
    {
        T retV = null;

        try {retV = (T) getSetting(key);}catch (ClassCastException ignored){}

        return retV;
    }

我通过使用它从设置注册表中提取文件来测试该方法,如下所示:

File f = configIO.getSettingAutocast("file");

注册表已在该键地址处预加载了 File 对象。

这按预期工作。但是,如果我将File 换成Integer,事情就不那么顺利了——我得到了ClassCastException。在调试模式下查看它,T 是方法开始时的正确类型,但是当调用强制转换时,它只是变形为 getSetting 返回的任何类型。

我的印象是编译器试图从目标对象(在本例中为FileInteger)推断&lt;T&gt;,而不是方法体本身中的任何类型。如果有人能提供更多关于编译器在方法方面如何处理类型推断的见解,将不胜感激。

【问题讨论】:

    标签: java generics casting type-inference


    【解决方案1】:

    您仍然收到 ClassCastException 传播的原因是此方法实际上没有强制转换。

    类型擦除后,赋值为:

    retV = (Object) getSetting(key);
    

    这当然成功了,因为一切都是对象(除非它是原始的,但你不能在这里使用泛型)。

    演员实际上被踢到了呼叫现场:

    Integer = (Integer) configIO.getSettingAutocast("file");
    

    (尝试反编译代码,您会在此处看到checkcast 指令)。

    所以 是引发异常的地方,正如您应该从堆栈跟踪中注意到的那样。

    我印象中...

    不。通过使用这种模式,您将得到您应得的。强制转换是告诉编译器信任你的一种方式,因为你知道一些它不知道的类型信息;在这种情况下,您只是在猜测类型,然后弄错了。

    返回对象,并在调用现场检查类型。是的,它会更丑;但是丑陋的代码比漂亮但损坏的代码要好。您施放的这一事实应该让您停下来考虑一下可能这里出了什么问题,而不是把它隐藏在这个方法中。

    【讨论】:

    • 对,这正是我得到的。但是,我在这里尝试完成的是检查方法inside 的对象类型的某种方式,而不是在方法本身的调用站点进行检查。本质上,我要做的是检查检索到的对象(从getSetting 返回)是否与目标对象的类型相同,由推断的类型变量T 指定(理论上)。还有另一种我不知道的方法吗?还是这个过程只是对这样一个系统提出了太多要求?
    • @Michael 这根本不可能。被调用的方法不会获得有关使用返回值(如果有)的上下文的信息。方法的返回类型不是其签名的一部分,因此您甚至无法通过重载来解决它。您所能做的就是拥有单独的方法(例如getFileSettinggetIntegerSetting),然后调用泛型方法/在那里进行强制转换;或提供Class&lt;T&gt;(或类似)参数,以便您的通用方法可以检查值是否匹配。
    • 我很害怕——但这并不是我没有预料到的。我从摘录中获得了有关类型推断和类型变量转换的信息,例如:"...推断算法确定参数的类型,如果可用,还确定分配或返回结果的类型。最后,推理算法试图找到适用于所有参数的最具体的类型。” 但是,如果在运行时不知道返回值的用途,那么我想我将不得不依靠手动转换。无论如何,感谢您的时间和帮助。
    猜你喜欢
    • 2014-08-27
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2023-03-08
    • 2019-04-27
    相关资源
    最近更新 更多