- 1 1. 本文你将学到的内容(先看结论)
- 2 2. Java 的 long 类型是什么?(基础定义)
- 3 3. 正确理解 long 的取值范围(最大/最小)
- 4 4. 为什么数值字面量需要 “L” 后缀(最令人困惑的点)
- 5 5. 与 long 的基本操作(赋值、计算、类型转换)
- 6 6. 溢出行为和对策
- 7 7. long 与 Long 的区别(基本类型 vs 包装类)
- 8 8. String ↔ long 转换(输入、配置和外部数据必备)
- 9 9. long 的实际用例(真实世界示例)
- 10 10. (高级)将 long 视为无符号数
- 11 11. 总结(关于 long 的最重要要点)
- 12 12. 常见问题解答(FAQ)
1. 本文你将学到的内容(先看结论)
在 Java 中,long 是一种 用于安全处理大整数的原始类型。
然而,初学者常会遇到一些常见的卡点。本文将整理出搜索 java long 的人最可能想了解的内容,并一步步解释,让你能够以清晰、合乎逻辑的顺序理解它。
1.1 快速了解 long 的作用(“它到底有什么用?”变得清晰)
long 是 64 位有符号整数,因此它能处理比 int 大得多的数字。
这也是它常被用于以下场景的原因:
- ID(例如可以增长到非常大的数据库序列)
- 时间(UNIX 时间的毫秒数、日志时间戳等)
- 金钱(当你想避免小数并以最小单位的整数来管理金额时)
换句话说,如果你要处理的整数 可能会变得很大,long 就显得尤为重要。
1.2 能够准确说明 long 的取值范围(最大值/最小值)
“long 能有多大?”是实际工作中经常出现的问题。
本文将使用 Long.MAX_VALUE 和 Long.MIN_VALUE 来说明 如何安全地理解和处理其范围。
我们还会明确解释常见的困惑,例如:“为什么即使 long 应该能容纳比 int 更大的值,却仍然报错?”
1.3 理解数值字面量为何需要 “L”(终于弄明白了)
这是关于 long 最常被搜索且最令人困惑的部分:
123L中的L是什么?- 为什么给
3000000000赋值会报错? - 什么时候应该加上
L?
从 Java 默认把整数字面量视为 int 这一关键前提出发,我们会仔细解释为何必须使用 L。
一旦弄懂了,你对 long 的认识将更加稳固。
1.4 学会 overflow(溢出)是如何产生的(以及如何防止)
long 能处理大数字,但它 不是无限的。
如果计算超出最大值,你可能会看到看似“错误”的结果(这就是溢出)。
本文将涵盖:
- 溢出现象的常见示例
- 溢出产生的原因(不涉及过于困难的细节)
- 实用的对策(如何安全地进行计算)
…所有内容都以初学者友好的方式进行解释。
1.5 理解 long 与 Long 的区别(原始类型 vs 包装类)
Java 同时拥有 long 和 Long。
它们看起来相似,容易混淆,但用途不同。
long:原始类型(速度快,不能为null)Long:类(拥有方法,可以为null)
我们会把这种区别梳理清楚,让你把它当作真实的 “如何选择” 决策,而不是单纯的记忆点。
1.6 阅读本文后的目标
阅读完本文后,你应该能够:
- 判断何时使用
long,何时int已足够 - 解释
L的含义并自行修复相关错误 - 使用
Long.MAX_VALUE等常量安全地处理边界 - 在中间计算中避免溢出和类型转换陷阱
- 根据具体情况恰当地使用
long与Long
达到这些目标后,你将摆脱 “我对 java long 还有点模糊” 的状态,能够自信地编写代码。
2. Java 的 long 类型是什么?(基础定义)
接下来,我们将巩固 long 类型的基础概念。
目标是超越 “它是一个能存放大数字的类型” 的表层认识,正确地把它当作语言规范来理解。
2.1 long 是 “64 位有符号整数类型”
在 Java 中,long 是 64 位(8 字节)有符号整数类型。
“有符号”意味着它同样可以表示 负数。
在内部,它具备以下特性:
- 位宽:64 位
- 支持的取值:正数、零以及负数
- 无小数(仅整数)
由于是 64 位,long 能处理的整数远大于 int。
long a = 10;
long b = -500;
long c = 1234567890123L;
所有这些赋值都可以正常工作。
2.2 与 int、short、byte 的区别
Java 除了 long 之外还有多种整数类型。
我们先在这里把“大小感受”整理一下。
| Type | Bits | Typical Use |
|---|---|---|
| byte | 8-bit | Binary data, low-level processing |
| short | 16-bit | Special cases (rarely used) |
| int | 32-bit | Standard for typical integer calculations |
| long | 64-bit | Large integers, IDs, time, etc. |
在实际工作中,基本的经验法则是:
- 普通计算 →
int - 可能会变大的整数 →
long
这就是选择的标准方式。
2.3 为什么不一开始就把所有东西都用 long?
初学者常会问类似的问题:
“既然
long能容纳更大的数字,为什么不在所有地方都直接使用long?”
技术上可以,但这 并不总是最佳选择。
原因如下:
int通常计算成本更低(CPU 更容易处理)- 在数组和大数据集下,内存使用会有所不同
- 许多 Java API 默认假设使用
int
所以,在实践中:
- 如果大小显然很小 → 使用
int - 如果将来可能增大或会溢出 → 使用
long
这通常是最实际的决策。
2.4 long 的常见真实场景使用
long 在以下情况下经常被使用:
2.4.1 ID 和顺序号
数据库主键或系统内部的唯一 ID 在长期运行后,
最终 会超过 int 的上限(约 21 亿)。
long userId = 10000000001L;
在这种情况下,几乎必须使用 long。
2.4.2 时间和日期(时间戳)
在 Java 中,时间通常以“毫秒为单位的整数”来处理。
long now = System.currentTimeMillis();
UNIX 时间的毫秒表示是一个非常大的数字,int 绝对不够用。
2.4.3 金额(以最小单位管理值)
当使用 double 处理金钱时,四舍五入误差会成为问题。
因此在真实系统中,常把金额以“最小单位”的整数来管理。
// Manage in units of 1 yen
long price = 1500;
这也是 long 的经典使用场景之一。
2.5 long 很“大”,但并非“无限”
这里有一个重要的提醒:
long能容纳很大的数字- 但它 并不是无限的
如果计算超出上限或下限,就会出现 溢出。
我们将在后面的章节详细讨论此问题。
3. 正确理解 long 的取值范围(最大/最小)
在使用 long 时,有一点 必须了解,那就是“数值范围”。
如果对这点认识模糊,容易导致意外的 bug 和计算错误。
3.1 在哪里可以查看 long 的最大值和最小值?
Java 提供了一种安全获取 long 范围的方式,作为 常量。
long max = Long.MAX_VALUE;
long min = Long.MIN_VALUE;
Long.MAX_VALUE:long能表示的最大值Long.MIN_VALUE:long能表示的最小值
你 不需要记住 这些具体数字。
重要的是知道“可以在代码中获取它们”。
3.2 long 的实际数值范围
供参考,long 的数值范围是:
- 最大值:9,223,372,036,854,775,807
- 最小值:-9,223,372,036,854,775,808
这是一串巨大的数字,直观上不易感受,但记住以下要点即可:
- 它可以处理约 9 千万亿(9 quintillion) 的数值
- 与
int(约 21 亿)的量级完全不同
这种概念模型通常已经足够。
3.3 为什么最大值和最小值不对称?
仔细观察会发现,long 的范围有点奇怪:
- 最大值:+9,223,372,036,854,775,807
- 最小值:-9,223,372,036,854,775,808
你可能会想,“为什么负数那边多了 1?”
这是因为 Java 整数采用 二补数(two’s complement)表示。
不必过度思考——只需记住:
设计上,负数那边会多出一个额外的取值。
掌握这个认识就足够了。
3.4 将 long 与 int 进行比较
现在让我们更具体地将其与 int 进行比较。
int intMax = Integer.MAX_VALUE; // 2,147,483,647
long longMax = Long.MAX_VALUE; // 9,223,372,036,854,775,807
int 的最大值约为 21 亿。
相比之下,long 的范围是 数百万倍更大。
由于这个差异,以下类型的值:
- 计数
- 时间(毫秒)
- 累计总和
- 顺序 ID
更有可能超出 int 能容纳的范围。
3.5 处理边界值时的注意事项
在 long 的最大值和最小值附近必须格外小心。
long value = Long.MAX_VALUE;
value = value + 1;
System.out.println(value);
如果运行这段代码,不会出现错误。
但打印的值不会是你期望的。
这种现象称为 溢出。
- 一旦值超过上限,它会环绕到负数范围
- Java 不会自动抛出溢出错误
如果你不了解这种行为,很容易会想,‘为什么它突然变成负数了?’
3.6 不要“记住”范围——要“保护”它
关键的思维方式是:
- 不要记住原始数字
- 使用
Long.MAX_VALUE/Long.MIN_VALUE - 对可能跨越边界的计算保持谨慎
只要保持这种思维方式,就能大幅减少与 long 相关的麻烦。
4. 为什么数值字面量需要 “L” 后缀(最令人困惑的点)
对于搜索 java long 的人来说,最令人困惑的话题往往是 在数值字面量后面添加的 “L”。
一旦正确理解它,许多与 long 相关的错误和疑惑会瞬间消失。
4.1 在 Java 中,整数字面量默认是 int
首先,有一个关键前提。在 Java 中,整数字面量默认被视为 int。
int a = 100;
这显然是没问题的。
但请看下面的代码:
long b = 3000000000;
乍一看似乎没问题,但 这会导致编译时错误。
原因很简单:
3000000000超出了int的范围- Java 首先尝试将其解释为
int - 此时被判断为“太大”
这就是错误产生的原因。
4.2 添加 “L” 后会有什么变化?
通过如下方式重写代码即可解决此错误:
long b = 3000000000L;
在数字末尾添加 L,可以明确告知 Java:
- “这个值是 long 字面量。”
- “从一开始就把它当作
long而不是int来处理。”
简而言之,L 是一个 明确指定类型的标记。
4.3 什么情况下需要 “L”?
在以下情况下需要使用 L:
4.3.1 编写超出 int 范围的数字时
long x = 2147483648L; // exceeds int max
在这种情况下,必须使用 L。
4.3.2 当你想显式标明为 long 时
即使该值在 int 范围内,你也可能想明确表示它应被视为 long。
long count = 100L;
这不是必须的,但可以提升可读性。
4.4 小写 “l” 可以使用吗?
从语法角度来看,这是合法的:
long y = 100l;
然而,不推荐使用小写 l。
原因很简单:
- 容易与数字 “1” 混淆
- 在代码审查时可能被误读
因此常见的规则是:始终使用大写 L。
4.5 十六进制、二进制、下划线与 L
long 字面量也可以使用十进制以外的进制表示。
long hex = 0x7FFF_FFFF_FFFF_FFFFL;
long bin = 0b1010_1010_1010L;
关键点:
_(下划线)可用作数字分隔符L放在 最末尾- 这大大提升了大数字的可读性
4.6 “L” 在表达式内部也很重要
下面的代码是经典的初学者陷阱:
long result = 1000 * 1000 * 1000;
虽然看起来没问题,但所有中间计算都是作为 int 执行的。
这可能会在计算过程中导致溢出。
正确版本是:
long result = 1000L * 1000 * 1000;
通过在开头添加 L,整个表达式作为 long 求值,使其安全。
4.7 “L” 不仅仅是为了避免错误
总结来说,L 的作用是:
- 明确告诉 Java “这是一个
long” - 安全处理超出
int范围的数字 - 防止中间计算中的溢出
- 清楚地向代码读者传达意图
不要将其视为一个单纯的符号,而是视为编写安全且可读代码的重要工具。
5. 与 long 的基本操作(赋值、计算、类型转换)
在这里,我们将整理使用 long 时总是会出现的关键点:赋值、算术运算和类型转换(casting)。
这是初学者经常说“我以为它会工作,但结果很奇怪”的地方,所以让我们仔细地过一遍。
5.1 long 的基本赋值
对 long 的赋值通常看起来像这样:
long a = 10;
long b = 100L;
int范围内的值 → 可以直接赋值- 超出
int范围的值 → 需要L
这直接源于我们之前的内容。
5.2 注意计算中的“类型提升”
Java 有一个规则,中间计算所使用的类型是自动确定的。
如果你不理解这一点,很容易导致微妙的 bug。
5.2.1 int × int 会产生 int
考虑这个例子:
long result = 1000 * 1000 * 1000;
处理顺序是:
1000 * 1000→int结果* 1000→ 仍然是int- 然后将结果赋值给
long
因为中间步骤保持为 int,在赋值之前可能会发生溢出。
5.2.2 从一开始就强制计算使用 long
为了避免这种情况,重要的是从一开始就提升到 long。
long result = 1000L * 1000 * 1000;
这确保了:
- 整个表达式作为
long求值 - 避免了中间溢出
这是最安全的方法。
5.3 隐式类型转换(安全情况)
在 Java 中,从小类型到大类型的转换 是自动执行的。
int x = 100;
long y = x; // OK
这种转换是安全的,因为不会丢失信息。
5.4 需要显式转换的情况(危险)
另一方面,窄化转换 如 long → int 需要特别小心。
long big = 3000000000L;
int small = (int) big;
这段代码可以编译,但值没有正确保留。
- 高位比特被截断
- 结果变成了一个完全不同的数字
换句话说,casting 不是“安全”的——它是“强制”的。
5.5 如何决定是否适合使用 casting
思考 casting 的安全方式是:
- “值保证适合
int” → casting 可能是可以接受的 - “我不知道未来它可能会如何变化” → 不要 casting
- “可能出现边界值” → 保持为
long
与其强制将值转换回较小的类型,通常最好继续使用足够大的类型。
6. 溢出行为和对策
long 可以处理非常大的数字,但一旦超过其限制,问题就不可避免。
在这里,我们将以初学者友好的方式解释为什么会发生溢出以及如何防止它。
6.1 即使是 long 也会发生溢出
首先,long 仍然是一个有限的类型。
因此,像下面的代码不会导致编译时错误,但在运行时会产生不正确的值。
long value = Long.MAX_VALUE;
value = value + 1;
System.out.println(value);
结果是一个非常大的负数,尽管你只是将 1 加到最大值上。
这不是一个 bug——它正是 Java 规范所规定的行为。
6.2 为什么数值会“环绕”?
Java 整数在内部使用二进制补码表示。
正因为这种表示方式:
- 超过了最大值
- 最高位会翻转
- 数值会环绕到负数范围
关键在于Java 不会自动检测溢出。如果不加防范,可能会在不知情的情况下继续使用无效的数值。

6.3 溢出成为问题的典型场景
在以下情形下需要格外小心:
- 累计的货币计算
- 递增计数器或累计总和
- 时间计算(添加持续时间)
- 自动生成 ID 或序列号
所有这些数值都会逐渐增长,意味着在长期运行中最终可能达到上限。
6.4 安全计算(使用 Math.addExact 等)
Java 提供了能够显式检测溢出的方法。
long result = Math.addExact(a, b);
该方法的行为如下:
- 结果在
long范围内 → 正常返回 - 超出范围 → 抛出
ArithmeticException
还有类似的方法:
Math.subtractExactMath.multiplyExact
在安全性至关重要的计算中,这些方法可以让你立即检测到异常情况。
6.5 通过 if 语句提前检查
你也可以在执行前通过条件判断来避免异常。
if (value > Long.MAX_VALUE - add) {
// Overflow may occur
}
这种做法在以下情况下很有用:
- 代码执行频率非常高
- 为了性能考虑想避免异常的开销
6.6 当 long 不足够时怎么办?
如果:
- 数值可能超出
long范围 - 精度极其重要(例如金融计算)
那么继续使用 long 并不是正确的选择。
在这种情况下,可以考虑:
BigInteger(任意精度整数)BigDecimal(任意精度小数)
不强行使用 long 也是良好设计的一部分。
7. long 与 Long 的区别(基本类型 vs 包装类)
Java 有两种非常相似的类型:long 和 Long。它们的用途截然不同,如果不了解如何正确使用,容易导致 bug 或设计错误。
7.1 long 与 Long 的根本区别
先把区别列出来。
| Item | long | Long |
|---|---|---|
| Type | Primitive | Class (Wrapper) |
| null allowed | No | Yes |
| Methods | None | Available |
| Memory efficiency | High | Slightly lower |
| Main usage | Calculations, high-performance logic | Collections, API integration |
简而言之:
- 数值计算的首选 →
long - 需要对象时 →
Long
这就是基本概念。
7.2 什么是 Long 类?
Long 是一个类,允许你把 long 值当作对象来使用。
Long a = 10L;
Long b = Long.valueOf(20);
使用 Long 可以:
- 表示
null - 使用转换和比较的方法
- 将数值存入集合(
List、Map等)
7.3 自动装箱与拆箱
Java 会自动在 long 与 Long 之间进行转换。
Long a = 10L; // Autoboxing (long → Long)
long b = a; // Unboxing (Long → long)
这很方便,但也伴随重要的注意事项。
7.3.1 当心 null 与运行时异常
Long a = null;
long b = a; // NullPointerException
如果在 Long 为 null 时进行拆箱,会抛出运行时异常。
因此:
- 值始终存在 →
long - 值可能缺失或未设置 →
Long
这个区别极其重要。
7.4 比较陷阱(== vs equals)
比较 Long 对象时,不要使用 ==。
Long a = 100L;
Long b = 100L;
System.out.println(a == b); // May be true
System.out.println(a.equals(b)); // Always true
== 比较的是引用,而 equals 比较的是数值。对于 Long,内部缓存机制会让行为显得尤为混乱。
始终使用 equals 比较值。
这是安全规则。
7.5 Long 类中常用的常量和方法
Long 类提供了实践中经常使用的功能。
Long.MAX_VALUE
Long.MIN_VALUE
这些常量对于安全处理 long 边界至关重要。
转换方法也很常见:
long x = Long.parseLong("123");
Long y = Long.valueOf("456");
parseLong:返回基本类型longvalueOf:返回Long对象
根据您的用例选择。
7.6 如何决定使用哪一个
如果不确定,请使用这些指南:
- 计算和数值逻辑 →
long - 可能有
null值 →Long - 存储在集合中 →
Long - 性能敏感的代码 →
long
在实践中,最稳定的方法是:默认使用 long,仅在必要时使用 Long。
8. String ↔ long 转换(输入、配置和外部数据必备)
在实际应用中,您更经常从字符串转换为 long,而不是直接在代码中编写它们。
- 表单输入
- CSV 或 JSON 数据
- 配置文件
- 环境变量
这里,我们将整理字符串和 long 之间安全且正确的转换方法。
8.1 String → long(解析数字)
将字符串转换为 long 的两种最常见方法是:
8.1.1 使用 Long.parseLong(最常见)
long value = Long.parseLong("12345");
- 返回类型:
long - 失败时:抛出
NumberFormatException
这是默认选择,当您希望在计算中使用该值时。
8.1.2 使用 Long.valueOf
Long value = Long.valueOf("12345");
- 返回类型:
Long - 可能使用内部缓存
这在将值存储在集合中或需要 null 处理时很有用。
8.2 处理转换失败和异常
以下字符串将转换失败:
Long.parseLong("abc");
Long.parseLong("12.3");
Long.parseLong("");
所有这些都会在运行时抛出 NumberFormatException。
在处理外部输入时,始终使用异常处理:
try {
long value = Long.parseLong(input);
} catch (NumberFormatException e) {
// Handle invalid numeric input
}
在实践中,切勿假设输入总是有效的。
8.3 long → String(用于显示和输出)
有几种将 long 值转换为字符串的方法。
8.3.1 使用 Long.toString
long value = 12345;
String text = Long.toString(value);
此方法专用于 long,并清楚地表达意图。
8.3.2 使用 String.valueOf
String text = String.valueOf(value);
这种方法也很常见,并提供 null 安全性。
8.4 应该选择哪种转换方法?
使用这些指南:
- 您需要用于计算的数值 →
Long.parseLong - 您需要一个对象 →
Long.valueOf - 显示或日志记录 →
String.valueOf/Long.toString
8.5 转换期间需要记住的关键点
始终牢记这些:
- 切勿盲目信任输入
- 编写代码时假设异常可能发生
- 注意边界值(MAX / MIN)
- 考虑数字长度的未来增长
遵循这些原则将大大减少与转换相关的错误。
9. long 的实际用例(真实世界示例)
现在我们已经涵盖了基础知识,让我们逐案查看为什么在真实世界系统中选择 long。
9.1 UNIX 时间和时间戳
在 Java 中获取当前时间的一种典型方法是:
long now = System.currentTimeMillis();
以毫秒为单位的 UNIX 时间已经远远超过 int 范围,因此 long 实际上是标准。
- 日志时间戳
- 测量执行时间
- 过期和超时处理
9.2 数据库 ID 和顺序键
大多数系统使用顺序 ID 来标识记录。
long userId;
long orderId;
在长时间运行期间:
- 记录计数可能超过数亿甚至数十亿
- 未来的扩展可能会增加位数
从一开始就使用 long 可以降低后期繁琐的类型更改风险。
9.3 金额管理(避免浮点误差)
使用 double 或 float 来表示金钱可能会产生四舍五入误差。
常见的解决方案是 使用 long 将金额存储为最小单位。
// Manage amounts in yen
long price = 1500;
- 精确的加减运算
- 更简洁的比较
- 更容易检测溢出
9.4 计数器、总计和累加器
持续增长的数值——例如访问计数——也是 long 的理想候选。
long totalCount = 0;
totalCount++;
即使数值起始很小,选择 long 也能为未来的增长做好准备。
9.5 哈希值和内部计算
在算法或内部处理时,你可能需要:
- 临时存储计算结果
- 比
int更大的范围,但不需要任意精度
long 往往提供了恰当的平衡。
9.6 “只用 long” 是否总是正确?
关键要点:
- 盲目使用
long并不总是正确的 - 但如果数值可能增长,它是一个强有力的候选
在设计阶段,只需思考:
- 预期的最大值
- 数值是否会随时间增长
就能让选择更加明确。
10. (高级)将 long 视为无符号数
Java 的 long 是 有符号整数。
如果你想最大化非负范围,需要采用不同的做法。
10.1 Java 没有无符号 long 类型
与 C 或 C++ 不同,Java 并未提供 无符号 long 类型。
long 始终使用以下范围:
-9,223,372,036,854,775,808+9,223,372,036,854,775,807
10.2 何时需要无符号语义
在实际使用中,你可能在以下场景需要无符号行为:
- 位运算结果
- 哈希值
- 网络协议编号
- 被视为原始数字的 ID 或令牌
10.3 在 Long 类中使用无符号方法
Long 类提供了用于无符号操作的方法:
Long.compareUnsigned(a, b);
Long.divideUnsigned(a, b);
Long.remainderUnsigned(a, b);
这使得:
- 保持内部表示为
long - 仅在比较或计算时应用无符号逻辑
10.4 将值显示为无符号
String text = Long.toUnsignedString(value);
这会将数值转换为字符串,仿佛它是无符号的。
10.5 不要强行使用无符号
对于典型的业务数据——金钱、计数、时间——
有符号 long 更安全、更直观。
将无符号处理视为 专用工具,而非默认选项。
11. 总结(关于 long 的最重要要点)
让我们回顾最关键的要点:
long是 64 位有符号整数- 适用于大整数(ID、时间、金钱等)
- 使用
Long.MAX_VALUE/Long.MIN_VALUE安全处理范围 - 必要时在数值字面量后加
L - 注意在中间计算中可能出现的
int溢出 - 即使是
long也可能发生溢出 - 使用
Math.addExact等方法确保安全 - 默认使用
long,仅在需要时使用Long - 不要低估字符串转换、边界或异常处理的复杂性
牢记这些要点,可帮助你避免大多数与 long 相关的问题。
12. 常见问题解答(FAQ)
12.1 问:long 的最大值和最小值是多少?
答:
你不必记住具体数字。
直接使用以下常量即可:
Long.MAX_VALUE;
Long.MIN_VALUE;
12.2 问:“L”后缀是否总是必需的?
答:
当 数值字面量超出 int 范围 时必须添加 L。
在希望计算以 long 进行时,添加 L 也很有帮助。
12.3 问:即使使用 long 也会发生溢出吗?
(此处可根据实际内容继续补充答案)
A.
是的。Java 不会自动抛出错误。
在检测很重要时使用 Math.addExact 等方法。
12.4 Q. 我应该使用 long 还是 Long?
A.
默认使用 long。
仅在需要 null 或集合时才使用 Long。
12.5 Q. 将字符串转换为 long 的正确方法是什么?
A.
最常见的方法是:
long value = Long.parseLong(str);
始终记得处理外部输入的异常。


