考虑以下代码:

public class ShortDivision {
public static void main(String[] args) {
short i = 2;
short j = 1;
short k = i/j;
}
}
编译产生错误
ShortDivision.java:5: possible loss of precision
found   : int
required: short
short k = i/j;
因为表达式i / j的类型显然是int,因此必须将其强制转换为short。
为什么i/j的类型不短?
因为将int转换为short可能会导致精度损失。 (-32768 / -1)
根据Java规范:
5.6.2 Binary Numeric Promotion
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value of a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.

对于二进制运算,会将小整数类型提升为int,运算结果为int。

编辑:为什么会这样?简短的答案是Java从C复制了此行为。更长的答案可能与以下事实有关:所有现代机器都至少执行32位本机计算,而实际上对于某些机器而言,执行8位和更高的运算可能会更困难。 16位运算。

另请参阅:C#中的OR-ing字节给出int

更进一步:对某些运算符的操作数执行二进制数值提升:-乘法运算符*,/和%

好的,我知道语言规范指出该语言应具有这种行为(否则,编译器首先不会产生错误)。但我不理解其背后的动机。他们为什么要在进行划分之前推广类型,而不是仅仅对短裤进行划分?

我的赌注是"这就是C语言中的方式"。 Java旨在吸引C ++程序员-要求事物保持一致

感谢您的链接,这似乎是一个足够合理的解释。

关于动机:让我们想象一下这种行为的替代方法,看看为什么它们不起作用:

备选方案1:结果应始终与输入相同。

加一个int和short的结果应该是什么?

两个短裤相乘会得到什么结果?一般而言,结果将适合一个int,但由于我们将其截短为短,因此大多数乘法将无声地失败。之后强制转换为int将无济于事。

备选方案2:结果应始终是可以代表所有可能输出的最小类型。

如果返回类型为short,则答案不一定总是可表示为short。

一个short可以容纳-32,768到32,767的值。然后,此结果将导致溢出:

short result = -32768 / -1; // 32768: not a short

因此,您的问题变成:为什么将两个整数相加不会返回很长的时间?两个整数的乘积应该是什么?长吗一个BigNumber可以覆盖平方最小值的情况?

备选方案3:选择大多数人在大多数时间可能想要的东西

因此结果应为:

int用于将两个短裤或任何int运算相乘。

如果添加或减去短裤,则将short除以任意整数类型,再乘以两个字节,则...

如果将一个字节向右移一个字节,则为byte;如果向左移一个字节,则为int。

等等...

如果没有特殊的逻辑,就很难记住所有的特殊情况。简单地说:整数运算的结果总是int。

人们想要的东西,与您再次设计的好主意并不总是相同的。 QWERTY键盘排列就是一个很好的例子。最初旨在减慢打字员的速度,使打字机不会阻塞。不过,我无法想象像Im那样使用其他任何工具。

@Peter Lawrey:是的。如果亨利·福特(Henry Ford)问人们应该制造哪种汽车,那么许多人就会要求一辆装有6匹而不是4匹马的小车。倾听用户的需求是一件好事,但有时您需要给他们一些不同于他们想要什么,因为他们甚至无法想象与以往不同的解决方案。

对于没有运算符重载的语言,为什么结果不小于(最大可能结果)或(接收容器的大小)?在大多数情况下,这样的规则所产生的代码比使用方法1所产生的算术上正确的结果要小或小。例如,如果变量是32位,则p=(x*y)z;将执行32x32-> 64乘法和64 / 32-> 32除法。如果p和z为16位,则将执行32x32-> 64乘法,64-> 32溢出检查的归约和32 / 16-> 16除法。

与设计Java时占主导地位的语言C / C ++保持一致只是一种设计选择。

例如,可以实现i * j,以便从字节=> short,short => int和int => long提升类型,这样可以避免溢出,但是不会。 (在某些语言中确实如此)如果需要当前的行为,可以使用强制类型转换,但是会丢失一些位。

类似地,可以从字节/短=>浮点数或整数/长=>双精度字提示i / j。