编译时出现不一致的“可能会有损失的从int到byte的转换”错误

30

请检查以下代码片段:

片段 #1

int a=20;
int b=30;
byte c= (a>b)? 20:30;
Error:
incompatible types: possible lossy conversion from int to byte
byte c= (a>b)? 20:30;

片段 #2

int a=20;
int b=30;
byte h1=70;
byte c= (a>b)? 20:h1;

代码片段 #3

int a=20;
int b=30;
byte h1=70;
byte h2=89;
byte c= (a>b)? h1:h2;

片段 #4

byte c= (true)? 20:30;

除了代码片段 #1 之外,所有这些代码都可以编译通过。为什么会出现这种行为呢?如果代码片段 #1 产生了“可能会有精度损失的转换”错误,那么代码片段 #2 和 #4 也应该如此,因为它们仍然包含类型为 int 的文字。为什么它们可以成功编译?


5
如果将 int 更改为 final int(常量),编译器将会发现变量 ab 的值在字节范围内 -128..127。对于 int 类型的变量,编译器不进行这样的评估,并且假定该变量可能会超出字节范围。 - Joop Eggen
5
@JoopEggen 但是为什么变量a和b的范围甚至数据类型很重要呢?(a>b)是一个条件,将评估为true或false,并基于此将20或30分配给变量c。我不明白为什么变量a和b的范围和数据类型很重要。重要的是字面量20和30或变量h1和h2的范围和数据类型,它们用于分配给变量c。但从代码-4中看来,变量a和b的数据类型和范围很重要。 - Jay Patel
当将一个较大的类型变量赋值给一个较小的变量时,通常会出现警告/错误,可能会导致信息丢失。但是有更好的答案来澄清Java的状态,我希望能够解决这个问题。 - Joop Eggen
2个回答

30

J.L.S 15.25.解释了这种行为。

片段#1:

如果第二个和第三个操作数具有相同的类型(可以是null类型),则这就是条件表达式的类型

第二个和第三个操作数都是int字面量,因此表达式的类型也是int,不能将其分配给一个byte变量而不进行显式转换。因此编译错误。

片段#2:

如果其中一个操作数的类型为T,其中T为byte、short或char,并且另一个操作数是类型为int的常量表达式(§15.28),其值可表示为类型T,则条件表达式的类型为T。

一个操作数是byte,另一个是可以表示为byteint字面量,因此表达式的类型为byte,可以分配给byte变量。

片段#3:

如果第二个和第三个操作数具有相同的类型(可以是null类型),则这就是条件表达式的类型

第二个和第三个操作数都是byte,因此表达式的类型为byte,可以分配给byte变量。

片段#4:

由于所有3个操作数都是常量,整个三元表达式是一个常量表达式,因此编译器将此表达式视为简单赋值 - byte c = 20; - 这是有效的。


7

这种行为在语言规范中有描述。


情况1和3被描述为相同的点:

如果第二个和第三个操作数具有相同的类型,则条件表达式的类型就是那个类型。

在情况1中,操作数是int类型,因此整个表达式是int类型,因此不兼容。在情况3中,操作数是byte类型,因此结果是兼容的。


情况2让我很惊讶:我也希望它失败,因为int操作数将导致条件表达式成为int类型。

然而,这种行为在以下点中有所描述:

如果其中一个操作数是T类型,其中T是byte、short或char,另一个操作数是类型为int的常量表达式(§15.28),其值可表示为T类型,则条件表达式的类型为T。

20是适合于byte的常量表达式,因此结果是byte。


情况4也由用于情况1和3的“相同类型操作数规则”进行描述;但是,现在该条件为常量使其成为常量表达式

在分配到更窄的类型变量时,int类型的常量表达式会被隐式缩小,如赋值上下文中所述:

如果变量是byte、short或char类型,并且常量表达式的值可表示为变量的类型,则可以使用缩小原始转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接