Java 会直接截断 double 的小数部分,而不是进行四舍五入,然后将整数部分赋值给 long 变量。

下面我将从核心方法、注意事项、完整代码示例和最佳实践几个方面详细解释。
核心转换方法
主要有两种方式可以实现 double 到 long 的转换,它们在底层行为上是等价的。
强制类型转换 (Casting)
这是最直接、最常用的方法,语法是在 double 变量前加上目标类型 (long)。
double myDouble = 123.45; long myLong = (long) myDouble; // myLong 的值将是 123
工作原理:
这种转换会直接丢弃 double 值的小数部分,只保留整数部分,这个过程也称为“截断”。

使用 longValue() 方法
Double 是 double 的包装类,它提供了一个 longValue() 方法,其效果与强制类型转换完全相同。
Double myDoubleObj = 123.45; long myLong = myDoubleObj.longValue(); // myLong 的值将是 123
工作原理:
longValue() 方法内部也是通过强制类型转换实现的,所以行为一致。
关键注意事项(非常重要!)
⚠️ 注意事项 1:精度丢失与截断
如前所述,转换是截断,不是四舍五入。
double d1 = 123.9; double d2 = -123.9; long l1 = (long) d1; // 结果是 123 long l2 = (long) d2; // 结果是 -123 System.out.println(l1); // 输出: 123 System.out.println(l2); // 输出: -123
可以看到,9 和 -123.9 的小数部分都被直接丢弃了。

⚠️ 注意事项 2:大数溢出
double 的表示范围远大于 long。double 可以表示非常大的数(0E20),而 long 的最大值是 Long.MAX_VALUE (即 9,223,372,036,854,775,807)。
如果一个 double 的值超出了 long 的表示范围,强制转换会得到一个没有意义的值。
// double 的值远大于 long 的最大值 double tooBig = 1.0e20; // 100,000,000,000,000,000,000 long result = (long) tooBig; System.out.println(result); // 输出一个看似随机的巨大负数: -727379968L // 这是因为 1.0e20 的二进制表示已经超出了 long 的精度范围,导致高位信息丢失,转换后是一个错误值。
在进行转换前,最好先判断一下 double 的值是否在 long 的范围内。
⚠️ 注意事项 3:浮点数精度问题
double 是浮点数类型,它在计算机中是近似存储的,有些小数无法被精确表示。
// 0.1 在二进制中是一个无限循环小数,无法精确表示 double d = 0.1 + 0.2; // d 的值实际上是 0.30000000000000004 long l = (long) d; // 结果是 0 System.out.println(l); // 输出: 0
虽然这个例子中转换结果符合预期(截断后为0),但它揭示了 double 本身的不精确性,这种不精确性在转换前就已经存在了。
完整代码示例
这个示例综合了上述所有要点。
public class DoubleToLongExample {
public static void main(String[] args) {
System.out.println("--- 1. 基本截断 ---");
double d1 = 123.999;
double d2 = -456.123;
long l1 = (long) d1;
long l2 = (long) d2;
System.out.println("double " + d1 + " 转换为 long: " + l1); // 输出 123
System.out.println("double " + d2 + " 转换为 long: " + l2); // 输出 -456
System.out.println("\n--- 2. 大数溢出 ---");
double tooBig = 1.0e30;
long overflowResult = (long) tooBig;
System.out.println("double " + tooBig + " 转换为 long: " + overflowResult); // 输出一个错误值
System.out.println("\n--- 3. 浮点数精度问题 ---");
double imprecise = 0.1 + 0.2; // 实际上是 0.30000000000000004
long fromImprecise = (long) imprecise;
System.out.println("double " + imprecise + " 转换为 long: " + fromImprecise); // 输出 0
System.out.println("\n--- 4. 使用 Double.longValue() 方法 ---");
Double myDoubleObj = 987.65;
long l3 = myDoubleObj.longValue();
System.out.println("Double " + myDoubleObj + " 转换为 long: " + l3); // 输出 987
}
}
最佳实践
如果你想在转换时进行四舍五入,而不是简单的截断,你应该使用 Math 类中的辅助方法,这些方法在四舍五入前会检查是否溢出。
四舍五入
double myDouble = 123.6; long roundedLong = Math.round(myDouble); // Math.round 返回 long System.out.println(roundedLong); // 输出: 124 double myDouble2 = 123.4; long roundedLong2 = Math.round(myDouble2); System.out.println(roundedLong2); // 输出: 123
注意: Math.round() 的返回值类型是 long,所以可以直接赋值给 long 变量。
向上取整(天花板)
double myDouble = 123.1; long ceilingLong = (long) Math.ceil(myDouble); // Math.ceil 返回 double,需要强制转换 System.out.println(ceilingLong); // 输出: 124
向下取整(地板)
double myDouble = 123.9; long floorLong = (long) Math.floor(myDouble); // Math.floor 返回 double,需要强制转换 System.out.println(floorLong); // 输出: 123
| 需求 | 方法 | 说明 |
|---|---|---|
| 直接截断 | (long) myDouble |
最常用,直接丢弃小数部分。 |
| 直接截断 | myDoubleObj.longValue() |
与强制转换等价。 |
| 四舍五入 | Math.round(myDouble) |
推荐用于需要四舍五入的场景。 |
| 向上取整 | (long) Math.ceil(myDouble) |
返回不小于该数的最小整数。 |
| 向下取整 | (long) Math.floor(myDouble) |
返回不大于该数的最大整数。 |
核心建议:
- 如果只需要整数部分,明确知道会丢失小数,使用
(long) myDouble。 - 如果需要四舍五入,请使用
Math.round()。 - 在处理可能超出
long范围的极大double值时,务必小心,可能需要先进行范围检查。
