我遇到了一个我不太理解的奇怪问题,但它并不能阻止我的程序。我根据条件的结果设置short
变量的值,如果我使用标准的if/else,它可以正常工作,但如果我使用简写的条件赋值,它就不能正常工作。
这里有一个简单的例子:
public class ShortTest {
public static void main(String args []) {
int i = 0;
short s = 0;
// This always works
if( i < 100 )
s = 0;
else
s = 1;
// This causes an error
s = (i < 100)?1:0;
}
}
编译此代码的结果如下:
ShortTest.java:13: error: possible loss of precision
s = (i < 100)?1:0;
^
required: short
found: int
1 error
但是,如果将short
的强制转换添加到1
、0
或两者中,则效果良好。这三种说法都有效:
s = (i < 100)?(short)1:0;
s = (i < 100)?1:(short)0;
s = (i < 100)?(short)1:(short)0;
这没什么大不了的,因为if/else很好,但这让我抓狂。当这些值处于简写条件中时,它们不能自动从int
转换为short
,这是有原因的吗?为什么只选其中一个会突然让整个陈述变得有效?任何见解都将不胜感激!
1
和0
在这里被视为文字int
值,此操作的结果是int
,编译器无法缩小其范围。您应该显式添加强制转换:
s = (short) ((i < 100)? 1:0);
Java语言规范对此进行了解释。第15章。表达式。15.25.条件运算符?。
条件运算符有三个操作数表达式。
?
出现在第一和第二表达式之间,:
出现在第二和第三表达式之间。(…)
如果第二个和第三个操作数表达式都是数值表达式,则条件表达式是数值条件表达式。
(…)
数值条件表达式是独立表达式(§15.2)。
数值条件表达式的类型确定如下:
如果第二个和第三个操作数具有相同的类型,那么这就是条件表达式的类型
如果第二个和第三个操作数之一是基元类型T,而另一个操作数的类型是对T应用装箱转换(§5.1.7)的结果,则条件表达式的类型为T。
如果其中一个操作数的类型为byte或byte,另一个为short或short,则条件表达式的类型为short。
如果其中一个操作数是T类型,其中T是字节、短或字符,而另一个操作是int类型的常量表达式(§15.28),其值可在T类型中表示,则条件表达式的类型为T。
如果其中一个操作数是T类型,其中T是Byte、Short或Character,而另一个操作是int类型的常量表达式,其值可在类型U中表示,这是对T应用开箱转换的结果,则条件表达式的类型为U。
否则,二进制数字提升(§5.6.2)将应用于操作数类型,条件表达式的类型为第二个和第三个操作数的提升类型。
注意,二进制数字提升执行值集转换(§5.1.13),并可能执行开箱转换(§5.18)。
添加一些详细信息:正如已经指出的,整数文本的类型总是int
(当没有L
后缀时)。这样的声明:
s = 1; // where s is short
因此执行从int
到short
的窄幅转换。通常情况下,这种转换是不允许自动进行的。然而,JLS的§5.2有一些适用于常量表达式的特殊规则:
如果变量的类型是byte、short或char,并且常量表达式的值可以用变量的类型表示,则可以使用窄基元转换。
如果变量的类型为:,则可以使用缩小基元转换,然后进行装箱转换
字节,常量表达式的值可以用字节类型表示。
Short和常量表达式的值可以用Short类型表示。
字符和常量表达式的值可以用char类型表示。
这意味着这也是合法的:
s = 1 + 2;
但不幸的不是这样:
s = (i < 100) ? 1 : 0;
因为右边的表达式不符合常量表达式的定义。理论上,§5.2可以允许这种情况,方法是将第二个和第三个操作数都是常量表达式(或递归允许的条件表达式)的第二个操作数应用于常量表达式或应用于条件表达式。我不知道这是否值得作为一种语言改变来建议。