为什么 7/3 并不总是整数?为什么它可以被赋值给 byte 或 short,而 x/3 却不能?

4

我认为任何算术表达式的结果至少是一个int。7 / 3是一个表达式 - 它有一个操作符(除法)。

但是为什么这个可以编译通过呢?

byte b1 = 7 / 3;     // 7/3 is not a literal?
short b2 = 7 / 3;    // 7/3 is not a literal?
char b3 = 7 / 3;     // 7/3 is not a literal?

那 f1() 编译通过了吗?

byte f1() {
    return 7 / 3;    // Why is it allowed?  Why isn't 7 / 3 an int ?
}

byte f2(int x) {
    return x / 3;   // c.ERR - type mismatch
}

byte f3(byte x) {
    return x / 3;   // c.ERR - type mismatch
}

附言:这个问题和其他不同,因为我知道整数除法(向零取整)7 / 3 的结果是2,但它应该是int类型,而不是byte或short。


9
它始终是一个“int”。详情请参见JLS-5.1.3. 窄化原始类型转换 - Elliott Frisch
相关:https://dev59.com/2XE95IYBdhLWcg3wkeqq、https://dev59.com/xnzaa4cB1Zd3GeqPTbSj和https://dev59.com/-GEi5IYBdhLWcg3wZ7ga。(我无法找到一个适当解释将`7/3`分配给`byte`的答案,尽管[我在这里的回答](https://dev59.com/-GEi5IYBdhLWcg3wZ7ga#21317904)已经解释了对于基本相同规范的`char`。) - Radiodef
1个回答

11
byte f1() {
    return 7 / 3;    // Why is it allowed?  Why isn't 7 / 3 an int ?
}

在上面的代码片段中,结果在字节范围内(-128127),编译器足够聪明以意识到它可以将int结果隐式转换为byte并由您的方法返回。 JLS 14.17:当一个带有Expressionreturn语句出现在方法声明中时,Expression必须可赋值(§5.2)给方法声明的返回类型,否则会出现编译时错误。 JLS 5.2:如果表达式是byteshortcharint类型的常量表达式(§15.28):
  • 如果变量是byteshortchar类型,并且常量表达式的值可以表示为变量类型的值,则可以使用缩小的原始转换。

byte f2(int x) {
    return x / 3;   // c.ERR - type mismatch
}

在上面的代码片段中,因为x是一个int,它可以是一个大数,在除以3时,不会在byte范围内,所以编译器知道它不应该尝试将其隐式转换为byte,因为这个结果可能不是想要的。 JLS 14.17: 当一个带有表达式return语句出现在方法声明中时,表达式必须可分配(§5.2)到方法声明的返回类型,否则将会发生编译时错误
byte f3(byte x) {
    return x / 3;   // c.ERR - type mismatch
}

在上面的代码片段中,当使用一个byte和一个int进行算术运算时,byte将自动向上转换为int(如JLS中定义)。这导致了与第二种情况相同的情况;尽管我们知道结果必须在byte范围内,但编译器不知道,因为除以3可能会变成乘以9999...JLS 15.17: 操作数进行二进制数字提升(§5.6.2)。 JLS 5.6.2: 根据以下规则,应用扩展基本类型转换(§5.1.2)将一个或两个操作数转换为指定类型:
- 如果任一操作数是double类型,则另一个操作数被转换为double类型。 - 否则,如果任一操作数是float类型,则另一个操作数被转换为float类型。 - 否则,如果任一操作数是long类型,则另一个操作数被转换为long类型。 - 否则,两个操作数都被转换为int类型

2
有道理。 - Antoniossss
1
添加了JLS引用。希望这样可以。 - Andreas
@Andreas 当然,看起来很棒。谢谢 :) - Jacob G.

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