编译器丢弃我的类型转换?

Dan*_*ana 8 java static-typing

我为使这段代码工作而必须做的事感到困惑.似乎编译器优化了我需要的类型转换,或者在这里我还有其他一些我不理解的东西.

我有各种对象存储在实现接口的数据库中Foo.我有一个对象,bar它保存我用来检索我的Foo对象的数据.bar有这些方法:

Class getFooClass()

Long getFooId()
Run Code Online (Sandbox Code Playgroud)

我将类和ID传递给具有此签名的方法,该方法委托给hibernate,后者根据其类和ID检索主题:

public <T> T get(Class<T> clazz, Serializable id);
Run Code Online (Sandbox Code Playgroud)

有不同的实现者Foo,其中一些hibernate对象有Longid,而其他有Integerid.虽然这种方法接受了,但更远的地方最好接受正确的方法.因此,当我尝试调用get()带有Integerid 的对象时,如下所示,我可以理解地抱怨我提供了Long一个Integer需要的位置:

    get(bar.getFooClass(), bar.getFooId());
Run Code Online (Sandbox Code Playgroud)

这里有没有休眠的问题,我只需要提供一个Integer地方的Integer需要ID和Long其中一个Long是必需的ID.所以我添加了一个方法bar,hasLongId()和试过这:(在这一点上,你可能会想,这不是一个很好的设计,但现在这不是我的问题)

get(bar.getFooClass(),
    bar.hasLongId() ? bar.getFooId() : bar.getFooId().intValue());
Run Code Online (Sandbox Code Playgroud)

它仍然抱怨我提供了一个Long.这看起来很奇怪.然后我尝试了这个:

get(bar.getFooClass(),
    bar.hasLongId() ? bar.getFooId() 
                    : new Integer(bar.getFooId().intValue()));
Run Code Online (Sandbox Code Playgroud)

同样的错误!怎么会这样?所以我介入调试器,是的,它逐步完成intValue()并通过Integer构造函数,但是在get方法中,传递的参数实际上是一个Long- Long从返回的同一个对象getFooId().

我不明白发生了什么,所以我只是尝试各种各样的事情:

Integer intId = bar.getFooId().intValue();
get(bar.getFooClass(), bar.hasLongId() ? bar.getFooId() : intId);   
// same error
Run Code Online (Sandbox Code Playgroud)

Serializable id = bar.hasLongId() ? bar.getFooId() 
                                : new Integer(bar.getFooId().intValue());
get(bar.getFooClass(), id); 
// same error
Run Code Online (Sandbox Code Playgroud)

最后:

Serializable id;
if (bar.hasLongId()) {
    id = bar.getFooId();
} else {
    id = bar.getFooId().intValue();
}
get(bar.getFooClass(), id);
Run Code Online (Sandbox Code Playgroud)

这个工作.显然它与三元运算符有关.但为什么?有人可以解释这里发生了什么吗

And*_*erg 10

这是一个很好的问题,并且涉及三元表达式语义的细节.不,你的编译器没有破坏或玩弄你.

在这种情况下,如果三元表达式的第二个和第三个操作数的类型是longint,那么结果类型总是如此long.这是由于二进制数字促销.

根据JLS(Java语言规范):

...,二进制数字提升应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型.

由于二进制数字促销的规则#1,这些值将被取消装箱:

如果任何操作数是引用类型,则进行拆箱转换

这实际上意味着,当你有一个三元表达式时,表达式的结果类型必须是静态可确定的(在编译时).必须将第二个和第三个操作数强制转换为单个类型,这是表达式的类型.如果两个操作数都是数字类型,则二进制数字提升会启动以确定表达式的最终类型.