平時在儲存整數的時候, Java 中預設是 int 型別, int 型別有取值範圍: -2147483648 ~ 2147483647. 如果數字過大, 我們可以使用 long 型別, 但是如果 long 型別也表示不下怎麼辦呢?
long 型別最大可以儲存的數字 (二進位制形式):
轉為十進位制形式為:
就需要用到 BigInteger, 可以理解為非常非常大的整數.
有多大呢? 理論上最大到 42 億的 21 億次方, 基本上在記憶體撐爆之前, 都無法達到這個上限.
BigInteger 能表示的範圍很大, 從很小的數字如 1, 2, -1, -2, 到很大很大的數字, 只要是整數, 都可以表示.
BigInteger 類的常用的成員方法:
獲取 BigInteger 的物件有四種方法, 其中前三種為構造方法:
public BigInteger(int num, Random rnd) // 獲取隨機大整數, 範圍: [0 ~ 2 的 num 次方 -1]
public BigInteger(String val) // 獲取指定的大整數, 字串裡面必須是整數, 不能是小數或者 a b 等字母
public BigInteger(String val, int radix) // 獲取指定進位制的大整數
public static BigInteger valueOf(long val) // 靜態方法獲取 BigInteger 的物件, 內部有最佳化
BigInteger 物件一旦建立, 內部記錄的值是不能發生改變的.
程式示例:
public class Demo {
public static void main(String[] args) {
// 1. 獲取一個隨機的大整數
Random r = new Random();
BigInteger bd1 = new BigInteger(4, r);
System.out.println(bd1); // [0 ~ 15]
}
}
程式示例:
public class Demo {
public static void main(String[] args) {
// 2. 獲取一個指定的大整數, 可以超出 long 的取值範圍
// 細節: 字串中必須是整數, 否則會報錯
// BigInteger bd2 = new BigInteger("1.1"); // NumberFormatException: For input string: "1.1"
// System.out.println(bd2);
// BigInteger bd3 = new BigInteger("abc"); // NumberFormatException: For input string: "abc"
// System.out.println(bd3);
}
}
程式示例:
public class Demo {
public static void main(String[] args) {
// 3. 獲取指定進位制的大整數
// 細節:
// 1. 字串中的數字必須是整數
// 2. 字串中的數字必須要跟進位制吻合.
// 比如二進位制中, 那麼只能寫 0 和 1, 寫其他的就報錯.
BigInteger bd1 = new BigInteger("100", 10);
System.out.println(bd1); // 100
BigInteger bd2 = new BigInteger("100", 2);
System.out.println(bd2); // 4
// BigInteger bd4 = new BigInteger("123", 2); // NumberFormatException: For input string: "123" under radix 2
// System.out.println(bd4);
}
}
valueOf()
方法只能接受 long 型別的引數, 引數範圍超過了 long 的話, 方法無法接受, 就報錯了.
程式示例:
import java.math.BigInteger;
public class Demo {
public static void main(String[] args) {
// 4. 靜態方法獲取 BigInteger 的物件, 內部有最佳化
// 細節:
// 1. 能表示範圍比較小, 只能在 long 的取值範圍之內, 如果超出 long 的範圍就不行了.
BigInteger bd1 = BigInteger.valueOf(100);
System.out.println(bd1); // 100
// BigInteger bd2 = BigInteger.valueOf(10000000000000000000000000L); // Long number too large, java: 整數太大
// System.out.println(bd2);
}
}
程式示例:
import java.math.BigInteger;
public class Demo1 {
public static void main(String[] args) {
// 4. 靜態方法獲取 BigInteger 的物件, 內部有最佳化.
// 細節:
// 2. 在內部對常用的數字: -16 ~ 16 進行了最佳化.
// 提前把 -16 ~ 16 先建立好 BigInteger 的物件, 如果多次獲取不會重新建立新的.
BigInteger bd5 = BigInteger.valueOf(16);
BigInteger bd6 = BigInteger.valueOf(16);
System.out.println(bd5 == bd6); // true
BigInteger bd7 = BigInteger.valueOf(17);
BigInteger bd8 = BigInteger.valueOf(17);
System.out.println(bd7 == bd8); // false
}
}
檢視 BigInteger 的原始碼:
儲存 -16 ~ 16 這些 BigInteger 物件的方式:
0 這個 BigInteger 物件:
valueOf()
方法:
程式示例:
public class Demo1 {
public static void main(String[] args) {
// 5. 物件一旦建立內部的資料不能發生改變
BigInteger bd9 = BigInteger.valueOf(1);
BigInteger bd10 = BigInteger.valueOf(2);
// 此時, 不會修改參與計算的 BigInteger 物件中的值, 而是產生了一個新的 BigInteger 物件記錄結果 3
BigInteger result = bd9.add(bd10);
System.out.println(result); // 3
System.out.println(bd9 == result); // false
System.out.println(bd10 == result); // false
}
}
程式示例:
import java.math.BigInteger;
public class Demo2 {
public static void main(String[] args) {
/*
public BigInteger add(BigInteger val) 加法
public BigInteger subtract(BigInteger val) 減法
public BigInteger multiply(BigInteger val) 乘法
public BigInteger divide(BigInteger val) 除法, 獲取商
public BigInteger[] divideAndRemainder(BigInteger val) 除法, 獲取商和餘數
public boolean equals(Object x) 比較是否相同
public BigInteger pow(int exponent) 次冪
public BigInteger max/min(BigInteger val) 返回較大值/較小值
public int intValue(BigInteger val) 轉為int型別整數, 超出範圍資料有誤
*/
// 1.建立兩個BigInteger物件
BigInteger bd1 = BigInteger.valueOf(10);
BigInteger bd2 = BigInteger.valueOf(3);
// 2.加法
BigInteger bd3 = bd1.add(bd2);
System.out.println(bd3); // 13
// 3.除法, 獲取商和餘數
BigInteger[] arr = bd1.divideAndRemainder(bd2);
System.out.println(arr[0]); // 3
System.out.println(arr[1]); // 1
// 4.比較是否相同
BigInteger bd4 = BigInteger.valueOf(10);
BigInteger bd5 = BigInteger.valueOf(10);
boolean equal1 = bd4.equals(bd5);
System.out.println(equal1); // true
BigInteger bd6 = BigInteger.valueOf(10);
BigInteger bd7 = BigInteger.valueOf(1);
boolean equal2 = bd6.equals(bd7);
System.out.println(equal2); // false
// 5.次冪
BigInteger bd8 = bd1.pow(2);
System.out.println(bd8);
// 6.max
BigInteger bd9 = bd1.max(bd2);
System.out.println(bd9);
System.out.println(bd9 == bd1); // true
System.out.println(bd9 == bd2); // false
// 說明沒有建立新的 BigInteger 物件, 而是返回了比較大的那個值
// 7.轉為 int 型別整數, 超出範圍資料有誤
BigInteger bd10 = BigInteger.valueOf(2147483647L);
int i1 = bd10.intValue();
System.out.println(i1); // 2147483647
BigInteger bd11 = BigInteger.valueOf(2147483648L);
int i2 = bd11.intValue();
System.out.println(i2); // -2147483648, 出錯了
BigInteger bd12 = BigInteger.valueOf(200);
double v = bd12.doubleValue();
System.out.println(v); // 200.0
// 還有 longValue(), floatValue() 等方法
}
}
BigInteger 底層儲存方式:
對於計算機而言, 其實是沒有資料型別的概念的, 都是 0101010101.
資料型別是程式語言自己規定的.
這是一個超過 long 型別的數字以及它的二進位制補碼:
進入 BigInteger 的原始碼:
signum 成員變數表示 BigInteger 表示的數字的符號, 若 signum 是 -1, 則表示數字為負數, 若 signum 是 0, 則表示這個數字是 0, 若 sugnum 是 1, 則表示這個數字是正數.
mag 這個陣列儲存的就是資料, 由於資料很大, 所以將其拆分, 將一個很大的數拆成很多個小段, 每一個小段都會放到一個陣列當中.
signum 和 mag 兩種方式相結合, 就能表示大數字.
透過打斷點的方式檢視 BigInteger 物件:
Java 中, 陣列是有最大長度的, 陣列的最大長度是 int 的最大值: 2147483647.
在真實情況下, 電腦的記憶體一般是扛不住這麼大的陣列的, 即電腦的記憶體無法建立這麼大的陣列.
在此處, mag 陣列是 int 型別的. 因此, 陣列中每一位能表示的數字: -2147483648 ~ 2147483647
於是可以說,
陣列中最多能儲存元素個數: 21 億多
陣列中每一位能表示的數字個數: 42 億多
因此, BigInteger 能表示的最大數字為: 42 億的 21 億次方
實際中絕大部分電腦都沒有這麼大的記憶體, 因此可以認為 BigInteger 型別的數字是無窮大的.