我很困惑我必须做些什么才能使这段代码工作。似乎编译器优化了我需要的类型转换,或者还有其他我不理解的东西。
我有各种对象存储在实现接口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
这个有效。显然它与三元运算符有关。但为什么?有人能解释一下这里发生了什么吗?
答案 0 :(得分:10)
这是一个很好的问题,并且涉及三元表达式语义的细节。不,你的编译器没有破坏或玩弄你。
在这种情况下,如果三元表达式的第二个和第三个操作数的类型为long
和int
,则结果类型始终为long
。这是由于binary numeric promotion。
根据JLS (Java Language Specification):
...,二进制数字提升应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。
由于二元数字促销的规则#1,这些值已取消装箱:
如果任何操作数属于引用类型,则进行拆箱转换
这实际上意味着,当你有一个三元表达式时,表达式的结果类型必须是静态可确定的(在编译时)。必须将第二个和第三个操作数强制转换为单个类型,这是表达式的类型。如果两个操作数都是数字类型,则启动二进制数字促销以确定表达式的最终类型。