无法在 Java 中使用"(expr)?<val1>:<val2>"表示法设置短值

  • 本文关键字:val1 val2 设置 表示 Java expr java
  • 更新时间 :
  • 英文 :


我遇到了一个我不太理解的奇怪问题,但它并不能阻止我的程序。我根据条件的结果设置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的强制转换添加到10或两者中,则效果良好。这三种说法都有效:

s = (i < 100)?(short)1:0;

s = (i < 100)?1:(short)0;

s = (i < 100)?(short)1:(short)0;

这没什么大不了的,因为if/else很好,但这让我抓狂。当这些值处于简写条件中时,它们不能自动从int转换为short,这是有原因的吗?为什么只选其中一个会突然让整个陈述变得有效?任何见解都将不胜感激!

10在这里被视为文字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

因此执行从intshort的窄幅转换。通常情况下,这种转换是不允许自动进行的。然而,JLS的§5.2有一些适用于常量表达式的特殊规则:

此外,如果表达式是byte、short、char或int类型的常量表达式(§15.28):
  • 如果变量的类型是byte、short或char,并且常量表达式的值可以用变量的类型表示,则可以使用窄基元转换。

  • 如果变量的类型为:,则可以使用缩小基元转换,然后进行装箱转换

    • 字节,常量表达式的值可以用字节类型表示。

    • Short和常量表达式的值可以用Short类型表示。

    • 字符和常量表达式的值可以用char类型表示。

这意味着这也是合法的:

s = 1 + 2;

但不幸的不是这样:

s = (i < 100) ? 1 : 0;

因为右边的表达式不符合常量表达式的定义。理论上,§5.2可以允许这种情况,方法是将第二个和第三个操作数都是常量表达式(或递归允许的条件表达式)的第二个操作数应用于常量表达式应用于条件表达式。我不知道这是否值得作为一种语言改变来建议。

最新更新