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

时间:2016-09-21 00:12:26

标签: java static-typing

我很困惑我必须做些什么才能使这段代码工作。似乎编译器优化了我需要的类型转换,或者还有其他我不理解的东西。

我有各种对象存储在实现接口Foo的数据库中。我有一个对象bar,它包含我用来检索Foo个对象的数据。 bar有以下方法:

Class getFooClass()

Long getFooId()

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

public <T> T get(Class<T> clazz, Serializable id);

Foo有不同的实现者,其中一些hibernate对象具有Long id,而其他对象具有Integer id。虽然这种方法接受了,但更远的地方最好接受正确的方法。因此,当我尝试在get()内容为Integer的对象上调用Long时,我发现错误抱怨我提供了Integer,其中 get(bar.getFooClass(), bar.getFooId()); Integer需要:

Integer

这里没有休眠问题,我只需要提供Long,其中Long ID是必需的,bar需要hasLongId() id。所以我向get(bar.getFooClass(), bar.hasLongId() ? bar.getFooId() : bar.getFooId().intValue()); Long添加了一个方法,并尝试了这个:(此时你可能会认为这不是一个好的设计,但现在这不是我的问题)

get(bar.getFooClass(),
    bar.hasLongId() ? bar.getFooId() 
                    : new Integer(bar.getFooId().intValue()));

它仍抱怨我提供了intValue()。这看起来很奇怪。然后我尝试了这个:

Integer

同样的错误!怎么会这样?所以我介入调试器,是的,它逐步通过Long并通过Long构造函数,但是在get方法中,传递的参数实际上是getFooId() - 从Integer intId = bar.getFooId().intValue(); get(bar.getFooClass(), bar.hasLongId() ? bar.getFooId() : intId); // same error 返回的相同Serializable id = bar.hasLongId() ? bar.getFooId() : new Integer(bar.getFooId().intValue()); get(bar.getFooClass(), id); // same error 对象。

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

Serializable id;
if (bar.hasLongId()) {
    id = bar.getFooId();
} else {
    id = bar.getFooId().intValue();
}
get(bar.getFooClass(), id);

[Compare("OriginalPassword")]
public string ConfirmPassword { get; set; }

public string OriginalPassword
{
    get
    {
        return User.Password;
    }
}

最后:

Given an array of ints, return true if every element is a 1 or a 4.

only14([1, 4, 1, 4]) → true
only14([1, 4, 2, 4]) → false
only14([1, 1]) → true

这个有效。显然它与三元运算符有关。但为什么?有人能解释一下这里发生了什么吗?

1 个答案:

答案 0 :(得分:10)

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

在这种情况下,如果三元表达式的第二个和第三个操作数的类型为longint,则结果类型始终为long。这是由于binary numeric promotion

根据JLS (Java Language Specification)

  

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

由于二元数字促销的规则#1,这些值已取消装箱:

  

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

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