Java BigInteger 超大整数计算方法详解:创建、运算、比较与避坑

周末不加班
周末不加班
发布时间:2026-08-22 | 130人浏览过
原创

前言

在 Java 里,整数一旦超出 long 的上限,结果很可能已经错了,但程序本身并不会立刻报错。BigInteger 就是解决这类高精度整数问题的标准工具,不过它和基本类型的写法差异很大,尤其是创建、运算、比较和返回值处理,稍不注意就会踩坑。本文按实际开发最常见的问题展开,帮你快速判断什么时候该用它、该怎么用。

在 Java 开发里,int 和 long 虽然够快,但它们都有明确的取值上限。一旦数值超过范围,程序通常不会主动提醒,结果却已经发生溢出,排查时往往只能从异常业务结果倒推问题。

如果场景涉及超大整数、精确整数运算、进制处理,或者算法题中的高精度计算,就需要用到 java.math 包下的 BigInteger。下面按“为什么要用、怎么创建、怎么运算、哪些地方最容易写错”的顺序,把这套用法一次讲清楚。

为什么需要 BigInteger

int、long 等基本整数类型都只能表示固定范围内的数值。超过上限后,结果会直接溢出,而且这种错误往往是静默发生的,不会在编译或运行时自动提示。

这也是 BigInteger 存在的意义:它专门用于处理任意长度的整数,理论上只受 JVM 内存限制,适合以下几类场景:

  • 算法竞赛中的高精度整数运算
  • 金融统计里的大整数累计
  • 密码学、大数加密相关计算
  • 需要幂运算、取模、素数判断、进制转换的程序

BigInteger 的核心特点

在正式写代码前,先要明确 BigInteger 和基本类型的几个本质区别。

  • 支持超大整数:没有固定数值上限,主要受内存限制。
  • 不可变类:每次运算都会返回新的 BigInteger 对象,原对象本身不会被修改。
  • 不能直接用运算符:不支持 + - * / %,必须调用对应方法。
  • 整数精度无损:只要是整数运算,就不会出现精度丢失问题。
  • 性能弱于基本类型:底层处理成本更高,不适合高频、小数值的普通计算。

BigInteger 如何创建

BigInteger 没有无参构造,实际开发里常见的创建方式主要有 4 种。

BigInteger 创建方式对比信息图
BigInteger 创建方式一图看懂按数值来源选择 BigInteger 的创建方式,重点区分 long。

通过普通数值创建

适合仍然处在 long 范围内的数值,写法也最直接。

// 通过 long 数值创建(适合 long 范围内数值)
BigInteger num1 = BigInteger.valueOf(123456);
// 负数创建
BigInteger num2 = BigInteger.valueOf(-98765);

通过字符串创建超大整数

这是最常用、也最推荐的方式,尤其在数值已经超过 long 上限时,字符串构造几乎是唯一可靠选择。

// 远超 long 最大值的超大整数
BigInteger bigNum = new BigInteger("999999999999999999999999999999");

按指定进制创建

如果原始数据本身就是二进制、十六进制等字符串,可以在构造时直接声明进制。

// 将二进制 1010 转为十进制数字
BigInteger binaryNum = new BigInteger("1010", 2);
// 将十六进制转为十进制
BigInteger hexNum = new BigInteger("FF", 16);

直接使用系统常量

一些常见值已经有内置常量,没必要重复创建对象。

BigInteger.ZERO;    // 0
BigInteger.ONE;     // 1
BigInteger.TWO;     // 2
BigInteger.TEN;     // 10

常用算术运算怎么写

使用 BigInteger 时,最重要的一条规则就是:所有运算都会返回新对象,原对象不变。如果不接收返回值,这次运算等于没有生效。

BigInteger a = new BigInteger("100000000000000000000");
BigInteger b = new BigInteger("200000000000000000000");
// 1. 加法
BigInteger addRes = a.add(b);
// 2. 减法
BigInteger subRes = a.subtract(b);
// 3. 乘法
BigInteger mulRes = a.multiply(b);
// 4. 除法(整除,只取整数部分)
BigInteger divRes = b.divide(a);
// 5. 取模
BigInteger modRes = b.mod(a);
// 6. 求绝对值
BigInteger absRes = subRes.abs();
// 7. 取反
BigInteger negRes = a.negate();
// 8. 幂运算
BigInteger powRes = a.pow(3);
// 9. 最大/最小值
BigInteger maxRes = a.max(b);
BigInteger minRes = a.min(b);

如果只是做整除,divide() 就够用;如果还需要余数,下一节的 divideAndRemainder() 会更高效。

如何同时拿到商和余数

普通的 divide 只会返回商。在算法题、取模计算、分段处理等场景里,更常见的是一次同时拿到商和余数,这时可以用 divideAndRemainder。

BigInteger num = new BigInteger("100");
BigInteger divisor = new BigInteger("3");
// 数组:[0]商,[1]余数
BigInteger[] res = num.divideAndRemainder(divisor);
System.out.println("商:" + res[0]);
System.out.println("余数:" + res[1]);

返回值是一个数组,其中 res[0] 是商,res[1] 是余数。

BigInteger 该怎么比较大小

BigInteger 是对象,不是基本类型,因此不能用 >、<、== 直接比较数值大小或内容。

BigInteger 运算与比较规则信息图
运算、比较与返回值规则BigInteger 不能使用基本类型运算符和比较符,核心在于方法调用与返回值接收。
BigInteger x = new BigInteger("888");
BigInteger y = new BigInteger("666");
// compareTo:大于返回1,等于返回0,小于返回-1
int cmp = x.compareTo(y);
// 判断是否相等(推荐,杜绝 == 地址比较坑)
boolean eq = x.equals(y);
// 判断正负、零
boolean zero = x.equals(BigInteger.ZERO);
boolean positive = x.compareTo(BigInteger.ZERO) > 0;
boolean negative = x.compareTo(BigInteger.ZERO) < 0;

常见判断规则可以直接记成两条:

  • 比较大小用 compareTo()
  • 比较数值是否相等用 equals()

进制转换与类型转换

BigInteger 不只是做大数运算,也经常承担进制转换和类型转换的角色。

转为不同进制字符串

BigInteger num = new BigInteger("255");
String binary = num.toString(2);   // 转二进制
String oct = num.toString(8);     // 转八进制
String hex = num.toString(16);     // 转十六进制

转回基本类型时要注意范围

把大整数转成 long、int 时,最关键的问题是范围是否安全。原文提示“超出基本类型范围会抛异常”,实际编写这类代码时,最好先做范围判断,再决定是否转换。

// 转 long(范围溢出抛异常)
long longVal = num.longValue();
// 转 int
int intVal = num.intValue();
// 精准判断是否可以转为 long
boolean canLong = num.bitLength() <= 63;

位运算与常用工具方法

在算法和底层计算场景里,BigInteger 还提供了一整套位运算和工具方法。

BigInteger n = new BigInteger("10");
n.and(BigInteger.ONE);      // 与运算
n.or(BigInteger.ZERO);       // 或运算
n.xor(BigInteger.TWO);      // 异或运算
n.not();                    // 取反
n.shiftLeft(2);             // 左移(乘2^2)
n.shiftRight(1);            // 右移(除2)
// 获取二进制位数
int bitLen = n.bitLength();
// 判断是否为素数
boolean prime = n.isProbablePrime(50); // 参数为置信度

其中比较常见的几个用途包括:

  • bitLength():判断位数或辅助判断是否可安全转为基本类型
  • shiftLeft()、shiftRight():做高效的位移计算
  • isProbablePrime(50):快速进行素数判断

最容易踩坑的 4 个地方

1. 忘记接收返回值

BigInteger 是不可变类,调用方法不会直接改掉原变量。

// 错误写法
BigInteger a = BigInteger.TEN;
a.add(BigInteger.TEN);
System.out.println(a); // 仍然是10
// 正确写法
a = a.add(BigInteger.TEN);

2. 用 == 比较数值

== 比较的是对象地址,equals() 比较的是数值内容;涉及大小判断时,则应使用 compareTo()。

3. 把它当成基本类型写运算符

BigInteger 不支持 + - * / 这类运算符,必须改用 add()、subtract()、multiply()、divide() 等方法。

4. 超大数还想用 valueOf

只要数值已经超出 long 范围,就不能再通过 valueOf() 或字面量直接处理,应该改用字符串构造。

什么时候该用 BigInteger,什么时候不该用

选型时可以直接按场景判断:

BigInteger 易错点与选型建议信息图
常见坑与使用边界把常见错误和选型原则放在一起,便于在开发中快速判断是否应使用 BigInteger。
  • 普通整数,范围明确在 long 内:优先使用 long,性能更高。
  • 数值已经超过 long 范围:必须使用 BigInteger。
  • 高频循环、性能敏感场景:尽量继续使用基本类型,避免不必要的大数对象开销。
  • 算法题、大数加密、进制运算、素数判断:优先考虑 BigInteger。

一句话概括就是:BigInteger 解决的是“算得对”的问题,基本类型更擅长“算得快”的问题。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表