0Pricing
Java Academy · 课时

整数运算与溢出

理解整数除法、取模、溢出行为,以及如何检测溢出

整数运算与溢出 是 CoddyKit 上的免费 Java Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

整数算术与溢出

Java 整数的大小是固定的。当计算结果超过最大值或最小值时,会静默回绕,不会抛出异常。理解这一点可以避免难以发现的错误。

整数范围

每种整数类型都有由位宽决定的有限范围:

  • byte:-128 到 127
  • short:-32,768 到 32,767
  • int:-2,147,483,648 到 2,147,483,647
  • long:-9.2 × 10^18 到 9.2 × 10^18
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Long.MAX_VALUE);    // 9223372036854775807
System.out.println(Byte.MAX_VALUE);    // 127

溢出:静默回绕

将 Integer.MAX_VALUE 加 1 会回绕为 Integer.MIN_VALUE。这是二进制补码算术;Java 不提供任何保证,也不会抛出异常。

int max = Integer.MAX_VALUE;
System.out.println(max + 1); // -2147483648 (overflow!)

byte b = 127;
b++;  // wraps to -128
System.out.println(b); // -128

// Real bug: counting votes in a large election with int
int votes = Integer.MAX_VALUE;
votes += 100; // silently wrong
System.out.println(votes); // negative number!

使用 Math.addExact 检测溢出

Java 8+ 引入了 Math.addExact()、multiplyExact() 和 subtractExact(),它们会在溢出时抛出 ArithmeticException,而不是静默回绕。

try {
    int result = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
    System.out.println("Overflow detected!"); // prints this
}

try {
    long safe = Math.multiplyExact(100_000L, 100_000L);
    System.out.println(safe); // 10000000000
} catch (ArithmeticException e) {
    System.out.println("Multiply overflow");
}

整数除法与取模

整数除法会向零截断。% 运算符返回与被除数符号相同的余数。请注意除以零的情况,这会抛出 ArithmeticException。

System.out.println(10 / 3);    // 3 (not 3.33)
System.out.println(10 % 3);    // 1
System.out.println(-10 % 3);   // -1 (sign follows dividend)
System.out.println(-10 % -3);  // -1

try {
    int x = 5 / 0; // ArithmeticException: / by zero
} catch (ArithmeticException e) {
    System.out.println(e.getMessage()); // / by zero
}

// Float division by zero gives Infinity, not exception
System.out.println(5.0 / 0); // Infinity

使用 long 处理大数运算

当数值可能超出 int 的范围时,请使用 long。请始终在 long 字面量后添加 L,以避免在赋值前发生溢出。

// Bug: multiplication done as int, then widened
long wrong = 1_000_000 * 1_000_000;   // overflows int!
System.out.println(wrong); // -727379968 (wrong!)

// Fix: one operand is long
long correct = 1_000_000L * 1_000_000L;
System.out.println(correct); // 1000000000000

// Or cast first
long alsOk = (long) 1_000_000 * 1_000_000;
System.out.println(alsOk); // 1000000000000

位移运算符

位移运算符可以快速实现乘以或除以 2 的幂:

  • n << k — 左移:乘以 2^k
  • n >> k — 带符号右移:除以 2^k
  • n >>> k — 无符号右移:用 0 填充
int n = 8;
System.out.println(n << 1);  // 16 (8 * 2)
System.out.println(n << 2);  // 32 (8 * 4)
System.out.println(n >> 1);  // 4  (8 / 2)
System.out.println(n >> 2);  // 2  (8 / 4)

// Check if number is power of 2
boolean isPow2 = n > 0 && (n & (n - 1)) == 0;
System.out.println(isPow2); // true

按位 AND、OR、XOR

按位运算符作用于各个二进制位,常用于权限、标志位和底层协议。

int a = 0b1010; // 10
int b = 0b1100; // 12

System.out.println(Integer.toBinaryString(a & b)); // 1000 (AND = 8)
System.out.println(Integer.toBinaryString(a | b)); // 1110 (OR  = 14)
System.out.println(Integer.toBinaryString(a ^ b)); // 0110 (XOR = 6)
System.out.println(Integer.toBinaryString(~a));    // ...11110101 (NOT)

// Permission flags example
int READ  = 0b001;
int WRITE = 0b010;
int EXEC  = 0b100;
int perms = READ | WRITE; // user has read+write
System.out.println((perms & EXEC) != 0); // false — no exec

数字字面量中的下划线

Java 7+ 允许在数字字面量中使用下划线,以提高可读性。编译器会忽略这些下划线。

int million = 1_000_000;
long creditCard = 4_111_1111_1111_1111L;
double pi = 3.141_592_653_589_793;
int hex = 0xFF_EC_D1_2E;
int binary = 0b0001_0101_0110;

System.out.println(million);   // 1000000
System.out.println(creditCard); // 4111111111111111

使用 BigInteger 实现任意精度

当数值超出 long 的范围时,请使用 BigInteger。它不会溢出,但速度比基本类型慢。它适用于加密密钥、阶乘和天文数字等场景。

import java.math.BigInteger;

BigInteger factorial100 = BigInteger.ONE;
for (int i = 2; i <= 100; i++) {
    factorial100 = factorial100.multiply(BigInteger.valueOf(i));
}
System.out.println(factorial100.toString().length() + " digits"); // 158 digits

BigInteger a = new BigInteger("999999999999999999999999999999");
BigInteger b = new BigInteger("1");
System.out.println(a.add(b)); // 1000000000000000000000000000000

实践:防溢出的计数器

一种实现计数器的模式:使用 Math.addExact 安全处理溢出,并在发生溢出时回退到 Long.MAX_VALUE。

class SafeCounter {
    private long count = 0;

    public void increment() {
        try {
            count = Math.addExact(count, 1L);
        } catch (ArithmeticException e) {
            count = Long.MAX_VALUE; // cap at max
        }
    }

    public long get() { return count; }
}

SafeCounter sc = new SafeCounter();
sc.increment();
sc.increment();
System.out.println(sc.get()); // 2

快速检查

下面表达式的值是多少?

long result = 1_000_000 * 1_000_000;
System.out.println(result);

总结:整数运算与溢出

要点:

  • 整数溢出会静默回绕,默认不会抛出异常
  • 使用 Math.addExact/multiplyExact/subtractExact 检测溢出
  • 整数除法会向零截断;% 的符号遵循被除数
  • 当中间结果可能超出 int 的范围时,使用 long 字面量(L 后缀)
  • BigInteger 可以处理任意大的值,不会发生溢出
  • 位移运算符可以快速替代乘以或除以 2 的幂

常见问题解答

「整数运算与溢出」课时是免费的吗?

是的 — 「整数运算与溢出」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「整数运算与溢出」这节课中我会学到什么?

理解整数除法、取模、溢出行为,以及如何检测溢出 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「整数运算与溢出」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Math 类基础
  2. 整数运算与溢出
  3. 使用 BigDecimal 进行财务计算
  4. NumberFormat 与 printf
← 返回 Java Academy