Java long 最大值:Long.MAX_VALUE、范围与溢出(附示例)

目次

1. Java的 long 类型的最大值是什么?

Java的 long 类型的最大值是 9223372036854775807
它被定义为常量 Long.MAX_VALUE

首先,让我们确认这个结论。

public class Main {
    public static void main(String[] args) {
        System.out.println(Long.MAX_VALUE);
    }
}

输出:

9223372036854775807

换句话说,这就是你在 Java long 中可以存储的最大正数值。

1.1 long 最大值是 “9223372036854775807”

这个值可以用下面的公式表示:

2^63 - 1

关键点是为什么是 “63”。

  • long 类型是 64 位整数
  • 1 位用于符号(正/负)
  • 剩余的 63 位表示数值。

因此,

maximum value = 2^63 - 1

成为最大值。

*“位”是表示 0 或 1 的最小数据单元。

1.2 为什么它不是 2^64 − 1,尽管它是 64 位?

这是最容易让初学者困惑的点。

Java 的 long有符号整数
“有符号”意味着它可以表示正数和负数。

64 位的划分:

  • 1 位 → 符号
  • 63 位 → 数值

因此,最大的正数值是:

2^63 - 1

这就是原因。

“2^64 – 1” 适用于 无符号整数
Java 没有 unsigned long 类型。

⚠ 常见误解

  • × long 最大值是 18446744073709551615
  • ○ 正确:9223372036854775807

1.3 也检查一下 long 的最小值

最小值是与最大值一起必须记住的另一个重要项。

System.out.println(Long.MIN_VALUE);

输出:

-9223372036854775808

以公式形式:

-2^63

绝对值比最大值大 1,因为 Java 使用 二进制补码 来管理整数。

*二进制补码是计算机用来表示负数的标准机制。

常见陷阱与注意事项

  • 把它误认为 2^64-1
  • 认为存在无符号 long
  • 直接记忆数值时记错数字
  • 与 int(32 位)混淆

尤其是,把它与 int 的最大值 (2147483647) 混淆 是非常常见的。

2. 在 Java 中获取 long 的最大值

在处理 long 的最大值时,规则是:不要直接写出数字——使用常量
下面我们将解释获取它的安全且实用的方法。

2.1 使用 Long.MAX_VALUE(推荐)

在 Java 中,最大值在 java.lang.Long 类中定义。

long max = Long.MAX_VALUE;
System.out.println(max);

输出:

9223372036854775807

为什么要使用常量?

  • 防止数字/拼写错误
  • 提高可读性
  • 明确类型
  • 对未来的更改更具鲁棒性(规范更改不太可能,但更安全)

不需要特殊导入。
java.lang 包会自动导入。

2.2 直接写数字时的注意事项

你也可以直接写出最大值。

long max = 9223372036854775807L;

这里重要的部分是 结尾的 “L”

为什么需要 “L”?

在 Java 中,整数字面量(数值字面量)默认被视为 int,除非后面追加了其他标识。

这意味着:

long max = 9223372036854775807;  // Error

这会导致编译时错误。

原因:

  • 超出了 int 的范围
  • 未明确表明它是 long

正确写法:

long max = 9223372036854775807L;

⚠ 小写的 l 与数字 1 难以区分,建议使用 大写 L

2.3 硬编码的风险

“硬编码”指的是直接写出数值。

if (value == 9223372036854775807L) {
    // Processing
}

问题:

  • 含义不明确
  • 可维护性低
  • 其他开发者难以理解

推荐做法:

if (value == Long.MAX_VALUE) {
    // Processing
}

这使得代码的意图更加清晰。

Common Mistakes

  • 忘记在数值后添加 L,导致编译错误
  • 尝试将其赋值给 int 类型的变量
  • 写成 Long max = Long.MAX_VALUE;,但未考虑可能的空值处理(在使用包装类时)
  • 尝试使用 Math.pow(2,63) 进行计算(会得到 double 并引入精度问题)

*Math.pow() 返回 double,因此不适合精确的整数计算。

3. 当 long 超过最大值会发生什么?(Overflow)

long 类型只能处理有限的范围。
所以如果超过最大值,它不会抛出错误——其值会环绕(循环)。
这称为“溢出”。

3.1 实际的溢出示例

让我们在实践中验证一下。

public class Main {
    public static void main(String[] args) {
        long max = Long.MAX_VALUE;
        long overflow = max + 1;

        System.out.println("Max value: " + max);
        System.out.println("Max value + 1: " + overflow);
    }
}

输出:

Max value: 9223372036854775807
Max value + 1: -9223372036854775808

你可以看到 max + 1 变成了最小值

这并不异常——这是 Java 规范定义的行为。

3.2 为什么它不会变成错误?

Java 整数类型(int / long)在数值超出范围时不会抛出异常。

原因:

  • 位数固定(long 为 64 位)
  • 由于二进制补码表示,数值会环绕

从概念上讲:

Max value → +1 → Min value
Min value → -1 → Max value

计算机只是对位进行运算,因此没有“超出范围”的概念。

⚠ 常见的初学者困惑

  • 认为“会报错”
  • 符号突然翻转,导致 bug

3.3 如何检测溢出

普通的加法无法检测到溢出。

方法 1:使用 Math.addExact()(推荐)

try {
    long result = Math.addExact(Long.MAX_VALUE, 1);
} catch (ArithmeticException e) {
    System.out.println("Overflow occurred");
}

Math.addExact() 在结果超出范围时会抛出 ArithmeticException

还有:

  • Math.subtractExact()
  • Math.multiplyExact()

等。

3.4 如何进行范围检查

你也可以在加法前进行检查。

if (value > Long.MAX_VALUE - addValue) {
    System.out.println("Adding will overflow");
}

在实践中,addExact() 通常比这种方法更安全。

3.5 使用 BigInteger(无上限)

如果 long 不足,可使用 BigInteger

import java.math.BigInteger;

BigInteger a = new BigInteger("9223372036854775807");
BigInteger b = BigInteger.ONE;
BigInteger result = a.add(b);

System.out.println(result);

BigInteger 没有位数限制。

但请注意:

  • 比 long 更慢
  • 占用更多内存
  • 不是基本类型(而是对象类型)

Common Mistakes and Notes

  • 在货币计算中使用 long 而未注意溢出
  • 生成 ID 时未考虑上限
  • 使用 Math.pow 并引入精度误差
  • 转换为 double 再返回(精度损失)

这可能导致致命错误,尤其在金融处理时。

4. 与其他整数类型的最大值比较

要正确理解 long 的最大值,还需要了解它与其他整数类型的区别。在 Java 中,每种整数类型都有基于位宽的明确范围。

4.1 与 int 的区别

int32 位有符号整数

System.out.println(Integer.MAX_VALUE);

输出:

2147483647

比较:

TypeBit widthMaximum value
int32-bit2,147,483,647
long64-bit9,223,372,036,854,775,807

long 的取值范围约是 int 的 43 亿倍。

⚠ 常见错误

  • 认为 int 足够,后因增长导致溢出
  • 将数据库的 BIGINT 映射为 int

4.2 与 short 和 byte 的比较

让我们也检查一下更小的整数类型。

System.out.println(Short.MAX_VALUE);  // 32767
System.out.println(Byte.MAX_VALUE);   // 127
TypeBit widthMaximum value
byte8-bit127
short16-bit32767
int32-bit2147483647
long64-bit9223372036854775807

典型的使用场景:

  • byte → 数据压缩的使用场景
  • short → 小规模数值
  • int → 常规整数处理
  • long → 大型 ID 和时间戳

4.3 何时应该使用 long?

使用 long 的典型情况:

  • UNIX 时间戳(毫秒)
  • 数据库的 BIGINT 列
  • 大型顺序 ID
  • 文件大小(字节)

示例:

long timestamp = System.currentTimeMillis();

System.currentTimeMillis() 返回一个 long。
这是因为毫秒级的数值无法放入 int。

4.4 不必要使用 long 的风险

long 占用 8 字节。
int 占用 4 字节。

在处理大量数据时:

  • 内存使用增加
  • 缓存效率下降
  • 性能影响(取决于运行环境)

因此,

如果范围明显适合 int,就使用 int。

这是基本原则。

常见错误与注意事项

  • 数据库是 BIGINT,但 Java 使用 int
  • 将 JSON 数值接收为 int,尽管它们假设为 long
  • 隐式类型转换导致精度丢失
  • 直接将 Math.pow 的结果赋给 long

类型不匹配导致的 bug 在 API 集成中尤为常见。

5. 处理 long 最大值的实际场景

long 的最大值不仅是理论知识——在实际开发中它非常重要。
理解它至关重要,尤其是在数值溢出可能致命的流程中。

5.1 UNIX 时间戳

在 Java 中获取当前时间:

long now = System.currentTimeMillis();
System.out.println(now);

System.currentTimeMillis() 返回自 1970 年 1 月 1 日以来的毫秒数。

如果将其存入 int:

int now = (int) System.currentTimeMillis();  // Dangerous

数值会被破坏(仅保留低 32 位)。

⚠ 注意

  • 强制转换导致截断
  • 2038 年问题(基于 int 的时间戳限制)
  • 将秒误当作毫秒

使用 long 可避免 2038 年问题。

5.2 与数据库的集成(BIGINT)

在许多数据库中,BIGINT 是 64 位整数。

示例:

CREATE TABLE users (
    id BIGINT PRIMARY KEY
);

在 Java 端:

long id;

如果将其接收为 int:

  • 数据损坏
  • 达到上限时抛出异常
  • 缺乏未来可扩展性

⚠ 常见的真实错误

  • 起初认为 int 足够 → 后期位数不足
  • ORM 中类型映射错误
  • JSON 转换期间的数值精度问题(JavaScript 仅安全到 53 位)

5.3 ID 生成与上限

分布式 ID(例如 Snowflake 风格)通常使用 long。

示例:

long id = generateId();

原因:

  • 64 位空间足够大
  • 可以将序列、时间戳和机器 ID 分割为不同的位段

然而,从理论上讲,long 也有上限。

示例检查:

if (currentId == Long.MAX_VALUE) {
    throw new IllegalStateException("ID upper limit reached");
}

在实际中很少会达到该上限,但在系统设计时应予以考虑。

5.4 文件大小计算

获取文件大小:

File file = new File("example.txt");
long size = file.length();

对于大文件,int 并不够用。

⚠ 注意

  • 不要将 long 转换为 int
  • 数组索引是 int(这就是限制所在)

常见的真实错误

  • 在 JSON 中处理 long 时 JavaScript 会出现精度丢失
  • 更改数据库列类型后未同步更新 Java 代码
  • 使用 long 进行货币计算导致溢出
  • 设计持久化 ID 时未考虑上限

6. 关于 long 最大值的常见误解

long 的最大值是一个在搜索结果中存在许多误解的话题。
在这里,我们整理了最令人困惑的点。

6.1 Java 中没有 unsigned long

这对于有 C/C++ 经验的开发者来说尤其令人困惑。

Java 没有:

an unsigned long type

long 始终是一个 64 位有符号整数

因此,最大正值是:

2^63 - 1

这就是极限。

从 Java 8 开始,添加了以下方法:

Long.compareUnsigned(a, b);
Long.divideUnsigned(a, b);

然而,这些只是用于无符号操作的辅助方法——仍然没有 unsigned long 类型。

6.2 最大值不是 2^64 − 1

网上经常出现的错误信息:

18446744073709551615

这是无符号 64 位整数的最大值。

由于 Java 的 long 是有符号的:

The maximum value is 9223372036854775807

这才是正确的值。

差异总结:

TypeMaximum value
Signed 64-bit2^63 – 1
Unsigned 64-bit2^64 – 1

Java 使用前者。

6.3 BigInteger 和 long 是不同的

BigInteger 表示几乎没有上限的整数。

差异:

TypeUpper limitNature
longFixed 64-bitPrimitive type
BigIntegerVirtually unlimitedObject type

BigInteger:

  • 使用更多内存
  • 计算更慢
  • 比较需要使用 equals()

long:

  • 快速
  • 轻量级
  • 固定范围

根据您的用例选择。

6.4 使用 Math.pow 计算最大值很危险

不正确的示例:

long max = (long) Math.pow(2, 63) - 1;

问题:

  • Math.pow 返回 double
  • double 具有 53 位精度
  • 大整数会出现精度错误

正确方法:

long max = Long.MAX_VALUE;

常见困惑总结

  • 认为 unsigned long 存在
  • 将其误认为是 2^64 – 1
  • 尝试使用 Math.pow 计算它
  • 通过 double 转换破坏精度
  • 将 BigInteger 与 long 混淆

7. 总结(快速复习)

这里是您在实践中需要的关键点的简洁总结。

7.1 最终答案:long 最大值

  • 最大值:9223372036854775807
  • 常量:Long.MAX_VALUE
  • 公式:2^63 – 1
  • 类型:64 位有符号整数

验证代码:

System.out.println(Long.MAX_VALUE);

7.2 您必须遵循的基本规则

  • 不要硬编码数字最大值——使用 Long.MAX_VALUE
  • 编写 long 字面量时添加 L
  • 不要将其与 int 混淆
  • 溢出不会自动抛出异常

7.3 如何防止溢出

安全加法:

Math.addExact(a, b);

如果值可能超过极限:

  • 使用 BigInteger
  • 实现范围检查

7.4 实践中的重要点

  • 将 DB BIGINT 值作为 long 接收
  • 使用 long 处理 UNIX 时间戳
  • 在 JSON 集成中注意精度
  • 设计 ID 系统时考虑上限

7.5 最重要的检查清单

  • 您是否错误地使用了 2^64 – 1?
  • 您是否假设 unsigned long 存在?
  • 您是否使用 Math.pow 计算它?
  • 您是否将 long 转换为 int?
  • 您是否理解溢出时会发生什么?

long 的最大值不仅仅是需要记忆的东西——它是一个 影响您对整数类型整体理解的核心概念

FAQ

Q1. Java 的 long 的最大值是什么?

9223372036854775807
您可以使用 Long.MAX_VALUE 获取它。

Q2. long 有多少位?

它是一个 64 位有符号整数
1 位用于符号,其余 63 位表示值。

Q3. 如果超过 Long.MAX_VALUE 会发生什么?

不会发生错误。
它会环绕到最小值 (-9223372036854775808)。

System.out.println(Long.MAX_VALUE + 1);

Q4. Java 有 unsigned long 吗?

没有,作为一种类型。
Java 8 及更高版本提供了用于无符号操作的辅助方法,但类型本身始终是有符号的。

Q5. 有一种安全的方式来计算最大值吗?

不要直接计算它。始终使用:

Long.MAX_VALUE

Math.pow() 返回 double,因此对大整数不准确。

Q6. 我应该使用 int 还是 long?

  • 如果范围在约 21 亿以内 → 使用 int
  • 如果可能超过 → 使用 long

对数据库 BIGINT 列和时间戳使用 long。

Q7. long 能处理多少位数字?

最大值有 19 位数字:
9223372036854775807

Q8. long 与 BigInteger 有何区别?

  • long → 固定 64 位,速度快
  • BigInteger → 实际上无限制,较慢

如果范围适合 long,使用 long 是标准做法。