代码之家  ›  专栏  ›  技术社区  ›  Michael Runzler

动态类型化方法中的奇数型推理

  •  0
  • Michael Runzler  · 技术社区  · 7 年前

    在处理配置管理器对象时,我想实现一个方法,从管理器的内部索引中检索一个值,并将其自动转换为所需的类型,从而消除显式转换的需要。我认为这很容易,使用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 对于 Integer ,事情不太顺利-我 ClassCastException . 在调试模式下查看, T 是方法开头的正确类型,但调用cast时,它只会变形为 getSetting .

    我的印象是编译器试图推断 <T> 从目标对象(在本例中为 文件 整数 ),而不是方法体本身中的任何类型。如果有人能提供更多关于编译器在处理方法时如何处理类型推理的见解,那将不胜感激。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Andy Turner    7 年前

    你仍然得到 ClassCastException 传播的是此方法不会 事实上 铸造

    类型擦除后,赋值为:

    retV = (Object) getSetting(key);
    

    当然,这是成功的,因为一切都是一个对象(除非它是基元的,但这样你就不能在这里使用泛型)。

    演员阵容实际上被推到了呼叫站点:

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

    (尝试反编译代码,您将看到 checkcast 说明)。

    所以 那个 是引发异常的位置,您应该从堆栈跟踪中注意到这一点。

    我觉得。。。

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

    返回对象,并在调用站点检查类型。是的,它会更丑;但丑陋的代码胜过美丽但破碎的代码。仅仅是你施展的事实就应该让你停下来思考一下 可以 此处出错,而不是将其隐藏在此方法中。