杰瑞科技汇

Java long 转 int 会溢出吗?

下面我将从核心方法、风险、最佳实践三个方面详细解释。

Java long 转 int 会溢出吗?-图1
(图片来源网络,侵删)

核心转换方法:强制类型转换

在 Java 中,long 是 64 位整数,而 int 是 32 位整数,要将一个 long 值存入 int 变量,你必须使用强制类型转换(也称为显式转换或窄化转换)。

语法如下:

long longValue = ...;
int intValue = (int) longValue;

示例代码:

public class LongToIntExample {
    public static void main(String[] args) {
        // 情况一:在 int 范围内的 long 值,转换成功
        long long1 = 12345L;
        int int1 = (int) long1;
        System.out.println("long1: " + long1 + " -> int1: " + int1); // 输出: 12345
        // 情况二:超出 int 范围的 long 值,会发生数据丢失
        long long2 = 2147483648L; // int 的最大值是 2147483647
        int int2 = (int) long2;
        System.out.println("long2: " + long2 + " -> int2: " + int2); // 输出: -2147483648 (发生了溢出)
        // 情况三:负数的 long 值
        long long3 = -12345L;
        int int3 = (int) long3;
        System.out.println("long3: " + long3 + " -> int3: " + int3); // 输出: -12345
    }
}

主要风险:数据丢失和溢出

强制类型转换 int 时,Java 会直接截断 long 值的高 32 位,只保留低 32 位,这会导致两种主要问题:

Java long 转 int 会溢出吗?-图2
(图片来源网络,侵删)

a) 溢出

long 的值超出了 int 的表示范围时,就会发生算术溢出

  • int 的范围是: -2,147,483,6482,147,483,647 (即 -2^312^31 - 1)。
  • long 的值大于 2,147,483,647,转换后的 int 值会从负数开始计算。
  • long 的值小于 -2,147,483,648,转换后的 int 值会从正数开始计算。

示例:

long bigLong = 2147483648L; // 比 Integer.MAX_VALUE 大 1
int result = (int) bigLong;
// 2147483648 的二进制表示是 10000000 00000000 00000000 00000000
// 截断后,int 的符号位为 1,表示负数。
// 其值为 -2147483648,即 Integer.MIN_VALUE
System.out.println(result); // 输出: -2147483648

b) 精度丢失

long 的值本身在 int 的范围内,但由于它的字面量写法使用了 L 后缀,转换是安全的,但如果 long 的值包含了超出 int 范围的部分,那么高位的部分就会被“切掉”,导致精度丢失。

long longWithHighBits = 0xFFFF_FFFF_FFFFL; // 一个很大的数
int truncatedInt = (int) longWithHighBits;
// 只保留了低 32 位,即 0xFFFFFFFF,其十进制值为 -1
System.out.println(truncatedInt); // 输出: -1

最佳实践和安全转换

直接进行强制转换是危险的,因为它会静默地失败(不会抛出异常),在实际开发中,你应该在转换前进行检查,以确保数据的安全性。

手动范围检查(推荐)

这是最常用且最清晰的方法,在转换前,检查 long 值是否在 int 的范围内。

public static long safeLongToInt(long longValue) {
    // 检查是否在 int 的范围内
    if (longValue > Integer.MAX_VALUE || longValue < Integer.MIN_VALUE) {
        // 处理溢出情况,
        // 1. 抛出一个异常
        throw new ArithmeticException("Long value is out of int range: " + longValue);
        // 2. 返回一个默认值(如 Integer.MAX_VALUE 或 Integer.MIN_VALUE)
        // return Integer.MAX_VALUE;
        // 3. 或者记录日志并返回一个特殊值
    }
    return (int) longValue;
}
// 使用示例
public static void main(String[] args) {
    try {
        long value = 1234567890123L;
        int safeInt = safeLongToInt(value);
        System.out.println("转换成功: " + safeInt);
    } catch (ArithmeticException e) {
        System.err.println("转换失败: " + e.getMessage());
    }
}

使用 Math 类进行边界检查

Java 的 Math 类提供了一些工具方法,可以简化边界检查。

long longValue = ...;
// 检查是否小于等于 Integer.MAX_VALUE 且大于等于 Integer.MIN_VALUE
if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
    int intValue = (int) longValue;
    // 安全使用 intValue
} else {
    // 处理溢出情况
}

使用 NumberUtils (Apache Commons Lang / Spring)

如果你在使用像 Apache Commons Lang 或 Spring 这样的库,它们提供了非常方便的工具方法。

Apache Commons Lang:

// 添加依赖: org.apache.commons:commons-lang3
import org.apache.commons.lang3.math.NumberUtils;
long longValue = ...;
// 如果转换失败,返回 null
Integer intValue = NumberUtils.createInteger(String.valueOf(longValue));
// 或者使用更严格的转换方法
try {
    intValue = NumberUtils.toInt(Long.toString(longValue));
} catch (NumberFormatException e) {
    // 处理转换失败
}

方法 描述 优点 缺点
(int) longValue 强制类型转换 语法简单,直接 不安全,会静默溢出,可能导致难以发现的 bug
手动范围检查 在转换前判断 longValue 是否在 Integer 范围内 安全可控,逻辑清晰,可以自定义处理溢出的方式 需要手动编写代码
Math 类检查 使用 Math 类进行边界判断 代码简洁 和手动检查类似,只是写法不同
第三方库工具 使用如 NumberUtils 等工具类 代码简洁,功能强大 需要引入外部依赖

核心建议:

永远不要直接对一个可能超出 int 范围的 long 值进行强制转换。 在转换前,务必进行范围检查,或者使用能够安全处理溢出的方法,以确保程序的健壮性。

分享:
扫描分享到社交APP
上一篇
下一篇