Java 如何处理多种类型的精度?

How does Java handle precision across multiple types?

在 Java 当我打印这样的东西时

System.out.println(1.0f*1l));

我得到了

的输出
1.0

或与

System.out.println(((byte)1)*'A');

我得到了

的输出
65

在这两种情况下,其中一种比另一种大。 Longs 是 64 位,而 float 是 32 位,bytes 是 8 位,而 chars 是 16 位。尽管如此,Java 还是以较小的类型输出结果。这不会被认为是精度损失吗?

Java 根据可能值的范围加宽类型。这意味着 float 被认为比 long.

long 的整数运算也按int 执行。 byte * charint

Java 语言规范提供了一个规则列表,用于管理基于操作数类型的结果类型。

特别是第 4.2.4 节说

If at least one of the operands to a binary operator is of floating-point type, then the operation is a floating-point operation, even if the other is integral.

这解释了为什么 float "wins" 反对 long.

整数运算在5.6.2节有解释。具体来说,它说

Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

• 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.

这就是为什么在您的第二个示例中,结果 65 的类型为 int

你问的是 Binary Numeric Promotion (JLS 5.6.2)(强调我的):

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:

  1. If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).
  2. Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
    • 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.

表达式1.0f*1lfloatlong,所以long转换为float

表达式((byte)1)*'A'是一个byte和一个char,所以它们都被转换为int

除了其他详细说明规则的答案外,我认为也值得考虑为什么要这样。假设你这样做

2.7F * 2L

这个乘法的真正数学答案是 5.4。因此,如果答案是 long,则它必须是 5L(5 是最接近 5.4 的整数)。由于这种情况,将浮点值乘以整数的结果作为浮点值更有意义。如果打印以下代码行 5.

,我认为在 Stack Overflow 上会有更多关于此的问题
System.out.println(2.7F * 2L);

实际上它打印 5.4.

整数类型之间的所有操作(long除外)都用int完成也是有道理的。毕竟,byte 通常被认为是一个小数据包,而 char 通常被认为是一个字符。从这些角度来看,乘以 bytechar 值并不是真正有意义的。保持规则简单并仅使用 int 进行操作更有意义。