---
title: "04-数据类型详解"
aliases:
- "数据类型详解"
created: 2025-12-24
---
# 数据类型详解
---
## 一、数据类型概览
### **1.1 类型体系**
```drawio
```
### **1.2 基本类型一览表**
```drawio
```
---
## 二、整数类型详解
### **2.1 取值范围的本质**
```drawio
```
### **2.2 整数字面量**
```
// ═══════════════════════════════════════════════════════════════════════
// 整数字面量的各种表示形式
// ═══════════════════════════════════════════════════════════════════════
// 十进制(默认)
int decimal = 100;
// 二进制(0b 或 0B 开头,JDK 7+)
int binary = 0b1100100; // = 100
int binary2 = 0B1010_1010; // 可用下划线分隔,提高可读性
// 八进制(0 开头)
int octal = 0144; // = 100
// 十六进制(0x 或 0X 开头)
int hex = 0x64; // = 100
int hex2 = 0xFF; // = 255
// ═══════════════════════════════════════════════════════════════════════
// 长整型必须加 L 后缀
// ═══════════════════════════════════════════════════════════════════════
long small = 100; // OK,自动转换
long big = 10000000000L; // 必须加 L,否则编译错误
// long error = 10000000000; // ❌ 编译错误:整数太大
// 建议使用大写 L,小写 l 容易与数字 1 混淆
long value = 123456789L; // ✅ 推荐
long value2 = 123456789l; // ⚠️ 不推荐
// ═══════════════════════════════════════════════════════════════════════
// 数字中的下划线(JDK 7+)
// ═══════════════════════════════════════════════════════════════════════
int million = 1_000_000; // 一百万,更易读
long creditCard = 1234_5678_9012_3456L;
int binary3 = 0b1010_0101_1100_0011;
// 下划线的限制
// int error1 = _100; // ❌ 不能在开头
// int error2 = 100_; // ❌ 不能在结尾
// int error3 = 0_x64; // ❌ 不能在进制标识中
// double error4 = 3_.14; // ❌ 不能在小数点旁边
```
```drawio
```
### **2.3 整数溢出**
```java
public class OverflowDemo {
public static void main(String[] args) {
// 最大值 + 1 = 最小值(溢出)
int max = Integer.MAX_VALUE; // 2147483647
System.out.println("max = " + max);
System.out.println("max + 1 = " + (max + 1)); // -2147483648
// 最小值 - 1 = 最大值(下溢)
int min = Integer.MIN_VALUE; // -2147483648
System.out.println("min = " + min);
System.out.println("min - 1 = " + (min - 1)); // 2147483647
}
}
```
```drawio
```
**安全的算术运算**:
```java
// JDK 8+ 提供安全的算术方法,溢出时抛出异常
public class SafeMathDemo {
public static void main(String[] args) {
int a = Integer.MAX_VALUE;
int b = 1;
// 普通加法(静默溢出)
int result1 = a + b; // -2147483648,无任何提示
// 安全加法(溢出时抛出异常)
try {
int result2 = Math.addExact(a, b); // 抛出 ArithmeticException
} catch (ArithmeticException e) {
System.out.println("溢出!" + e.getMessage());
}
// 其他安全方法
Math.subtractExact(a, b); // 安全减法
Math.multiplyExact(a, b); // 安全乘法
Math.negateExact(a); // 安全取负
Math.incrementExact(a); // 安全自增
Math.decrementExact(a); // 安全自减
}
}
```
---
## 三、浮点类型详解
### **3.1 IEEE 754 标准**
```drawio
```
### **3.2 浮点数精度问题**
```java
public class FloatPrecisionDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 经典问题:0.1 + 0.2 ≠ 0.3
// ═══════════════════════════════════════════════════════════════
double a = 0.1;
double b = 0.2;
double c = 0.3;
System.out.println("0.1 + 0.2 = " + (a + b)); // 0.30000000000000004
System.out.println("0.1 + 0.2 == 0.3 ? " + (a + b == c)); // false
// ═══════════════════════════════════════════════════════════════
// 另一个例子
// ═══════════════════════════════════════════════════════════════
float f1 = 0.3f - 0.2f; // 0.100000024
float f2 = 0.2f - 0.1f; // 0.099999905
System.out.println("f1 = " + f1);
System.out.println("f2 = " + f2);
System.out.println("f1 == f2 ? " + (f1 == f2)); // false
}
}
```
```drawio
```
### **3.3 特殊浮点值**
```java
public class SpecialFloatDemo {
public static void main(String[] args) {
// 正无穷大
double posInf = Double.POSITIVE_INFINITY;
System.out.println("1.0 / 0.0 = " + (1.0 / 0.0)); // Infinity
System.out.println("Max * 2 = " + (Double.MAX_VALUE * 2)); // Infinity
// 负无穷大
double negInf = Double.NEGATIVE_INFINITY;
System.out.println("-1.0 / 0.0 = " + (-1.0 / 0.0)); // -Infinity
// NaN (Not a Number)
double nan = Double.NaN;
System.out.println("0.0 / 0.0 = " + (0.0 / 0.0)); // NaN
System.out.println("sqrt(-1) = " + Math.sqrt(-1)); // NaN
// NaN 的特殊性质
System.out.println("NaN == NaN ? " + (nan == nan)); // false!
System.out.println("NaN != NaN ? " + (nan != nan)); // true!
// 正确判断 NaN
System.out.println("isNaN ? " + Double.isNaN(nan)); // true
// 判断无穷大
System.out.println("isInfinite ? " + Double.isInfinite(posInf)); // true
System.out.println("isFinite ? " + Double.isFinite(1.0)); // true
}
}
```
```drawio
```
---
## 四、字符类型
### **4.1 char 类型详解**
```drawio
```
```java
public class CharDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// char 的各种写法
// ═══════════════════════════════════════════════════════════════
char c1 = 'A'; // 字符字面量
char c2 = '\u0041'; // Unicode 转义
char c3 = 65; // 整数赋值
char c4 = '\n'; // 转义字符
System.out.println(c1 == c2); // true
System.out.println(c1 == c3); // true
// ═══════════════════════════════════════════════════════════════
// char 参与运算
// ═══════════════════════════════════════════════════════════════
char letter = 'A';
System.out.println(letter + 1); // 66 (int)
System.out.println((char)(letter + 1)); // B
// 大小写转换
char lower = 'a';
char upper = (char)(lower - 32); // 'A'
// 或使用 Character 类
upper = Character.toUpperCase(lower);
// ═══════════════════════════════════════════════════════════════
// 字符判断
// ═══════════════════════════════════════════════════════════════
char ch = '9';
System.out.println(Character.isDigit(ch)); // true
System.out.println(Character.isLetter(ch)); // false
System.out.println(Character.isLetterOrDigit(ch)); // true
System.out.println(Character.isWhitespace(' ')); // true
}
}
```
### **4.2 char 与 String 的区别**
```java
// ═══════════════════════════════════════════════════════════════════════
// char 与 String 的区别
// ═══════════════════════════════════════════════════════════════════════
char c = 'A'; // 单引号,基本类型,2 字节
String s = "A"; // 双引号,引用类型,对象
// 内存占用不同
char[] chars = {'H', 'e', 'l', 'l', 'o'}; // 10 字节
String str = "Hello"; // 对象头 + 引用 + char[] + ...(更多)
// 运算不同
System.out.println('A' + 'B'); // 131 (int 相加)
System.out.println("A" + "B"); // "AB" (字符串拼接)
System.out.println('A' + "B"); // "AB" (char 转 String 后拼接)
// 空值不同
char c1 = '\u0000'; // char 的"空"值
String s1 = null; // String 可以为 null
String s2 = ""; // String 可以为空串
```
### **4.3 常用转义字符**
```drawio
```
---
## 五、布尔类型
```java
public class BooleanDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// boolean 只有两个值
// ═══════════════════════════════════════════════════════════════
boolean flag = true;
boolean isEmpty = false;
// ═══════════════════════════════════════════════════════════════
// boolean 不能与其他类型转换
// ═══════════════════════════════════════════════════════════════
// int num = true; // ❌ 编译错误
// boolean b = 1; // ❌ 编译错误
// if (1) { } // ❌ 编译错误(不像 C/C++)
// 正确写法
int num = 1;
if (num != 0) { } // ✅ 显式比较
if (flag) { } // ✅ 直接使用 boolean
// ═══════════════════════════════════════════════════════════════
// boolean 的大小
// ═══════════════════════════════════════════════════════════════
// JVM 规范未明确定义 boolean 的大小
// 实际实现中:
// - 单个 boolean 通常占 4 字节(作为 int 处理)
// - boolean 数组中每个元素占 1 字节
}
}
```
```drawio
```
---
## 六、类型转换
### **6.1 自动类型转换(隐式转换)**
```drawio
```
```java
public class AutoConversionDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 自动类型转换
// ═══════════════════════════════════════════════════════════════
byte b = 10;
int i = b; // byte → int,自动转换
long l = i; // int → long,自动转换
float f = l; // long → float,自动转换
double d = f; // float → double,自动转换
char c = 'A';
int ic = c; // char → int,自动转换 (65)
// ═══════════════════════════════════════════════════════════════
// 精度损失示例
// ═══════════════════════════════════════════════════════════════
int bigInt = 123456789;
float floatVal = bigInt; // 自动转换,但有精度损失
System.out.println("int: " + bigInt); // 123456789
System.out.println("float: " + floatVal); // 1.23456792E8
System.out.println("转回int: " + (int)floatVal); // 123456792
long bigLong = 123456789012345678L;
double doubleVal = bigLong; // 精度损失
System.out.println("long: " + bigLong); // 123456789012345678
System.out.println("double: " + doubleVal); // 1.2345678901234568E17
}
}
```
### **6.2 强制类型转换(显式转换)**
```java
public class CastDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 大类型 → 小类型:需要强制转换
// ═══════════════════════════════════════════════════════════════
int i = 128;
byte b = (byte) i; // 必须强转
System.out.println("int 128 → byte = " + b); // -128 (溢出)
double d = 3.99;
int truncated = (int) d; // 截断小数部分
System.out.println("double 3.99 → int = " + truncated); // 3
// ═══════════════════════════════════════════════════════════════
// 强转可能导致数据丢失
// ═══════════════════════════════════════════════════════════════
int big = 300;
byte small = (byte) big;
System.out.println("int 300 → byte = " + small); // 44
// 原因分析:
// 300 的二进制: 00000000 00000000 00000001 00101100
// 截取低 8 位: 00101100 = 44
}
}
```
```drawio
```
### **6.3 表达式中的类型提升**
```java
public class TypePromotionDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 规则 1:byte、short、char 运算时自动提升为 int
// ═══════════════════════════════════════════════════════════════
byte b1 = 10;
byte b2 = 20;
// byte b3 = b1 + b2; // ❌ 编译错误,结果是 int
int i = b1 + b2; // ✅ 正确
byte b3 = (byte)(b1 + b2); // ✅ 强转
char c1 = 'A';
char c2 = 'B';
// char c3 = c1 + c2; // ❌ 编译错误
int ic = c1 + c2; // ✅ 正确,结果是 131
// ═══════════════════════════════════════════════════════════════
// 规则 2:表达式结果类型是最大的操作数类型
// ═══════════════════════════════════════════════════════════════
int a = 10;
long b = 20L;
float c = 1.5f;
double d = 2.5;
// int + long = long
long r1 = a + b;
// long + float = float
float r2 = b + c;
// float + double = double
double r3 = c + d;
// 混合运算:结果是 double
double r4 = a + b + c + d;
// ═══════════════════════════════════════════════════════════════
// 特殊情况:字面量
// ═══════════════════════════════════════════════════════════════
byte b4 = 10 + 20; // ✅ 编译期常量折叠,可以直接赋值
// byte b5 = b1 + 20; // ❌ 变量参与运算,结果是 int
final byte fb1 = 10;
final byte fb2 = 20;
byte b6 = fb1 + fb2; // ✅ final 常量,编译期可确定
}
}
```
---
## 七、包装类
### **7.1 基本类型与包装类对应关系**
```drawio
```
### **7.2 基本类型与包装类的区别**
```drawio
```
```java
public class WrapperDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 默认值差异
// ═══════════════════════════════════════════════════════════════
int primitiveInt; // 局部变量必须初始化
Integer wrapperInt = null; // 可以为 null
// ═══════════════════════════════════════════════════════════════
// 比较方式差异
// ═══════════════════════════════════════════════════════════════
int a = 100;
int b = 100;
System.out.println(a == b); // true,比较值
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false,比较地址
System.out.println(c.equals(d)); // true,比较值
// ═══════════════════════════════════════════════════════════════
// 泛型与集合
// ═══════════════════════════════════════════════════════════════
// List list; // ❌ 编译错误
List list = new ArrayList<>(); // ✅ 正确
list.add(1); // 自动装箱
// ═══════════════════════════════════════════════════════════════
// 空值表示场景
// ═══════════════════════════════════════════════════════════════
// 数据库查询结果可能为 null
Integer score = getScoreFromDB(); // 可能返回 null
if (score == null) {
System.out.println("成绩未录入");
}
}
}
```
### **7.3 自动装箱与拆箱**
```drawio
```
```java
public class BoxingDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 自动装箱
// ═══════════════════════════════════════════════════════════════
Integer a = 100; // Integer.valueOf(100)
Double b = 3.14; // Double.valueOf(3.14)
Boolean c = true; // Boolean.valueOf(true)
// ═══════════════════════════════════════════════════════════════
// 自动拆箱
// ═══════════════════════════════════════════════════════════════
int x = a; // a.intValue()
double y = b; // b.doubleValue()
boolean z = c; // c.booleanValue()
// ═══════════════════════════════════════════════════════════════
// 运算中的自动拆箱
// ═══════════════════════════════════════════════════════════════
Integer num1 = 10;
Integer num2 = 20;
int sum = num1 + num2; // 先拆箱再相加
// 等价于:
// int sum = num1.intValue() + num2.intValue();
// ═══════════════════════════════════════════════════════════════
// 比较中的陷阱
// ═══════════════════════════════════════════════════════════════
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1 == i2); // true (缓存)
System.out.println(i3 == i4); // false (超出缓存)
// 与基本类型比较时会自动拆箱
int p = 100;
System.out.println(i1 == p); // true (i1 拆箱后比较值)
}
}
```
**自动拆箱的 NPE 陷阱**:
```java
public class NullPointerDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 拆箱 null 会抛出 NullPointerException
// ═══════════════════════════════════════════════════════════════
Integer num = null;
// int value = num; // ❌ NullPointerException
// 等价于: int value = num.intValue(); // null.intValue() 报错
// 安全写法
int value = (num != null) ? num : 0;
// 或 JDK 9+
int value2 = Objects.requireNonNullElse(num, 0);
// ═══════════════════════════════════════════════════════════════
// 三元运算符的类型统一陷阱
// ═══════════════════════════════════════════════════════════════
Integer a = null;
Integer b = 10;
// 三元表达式要求两边类型一致
// 如果一边是基本类型,另一边会拆箱
Integer result = (a != null) ? a : 0; // OK
// Integer result2 = true ? null : 0; // NPE! null 被拆箱
}
}
```
### **7.4 包装类缓存机制**
```drawio
```
**Integer 缓存源码分析**:
```java
// Integer.java 源码(JDK 8+)
public final class Integer extends Number implements Comparable {
// valueOf 方法使用缓存
public static Integer valueOf(int i) {
// 如果在缓存范围内,直接返回缓存的对象
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
// 否则创建新对象
return new Integer(i);
}
// 内部缓存类
private static class IntegerCache {
static final int low = -128; // 最小值固定
static final int high; // 最大值可配置
static final Integer[] cache; // 缓存数组
static {
// 默认最大值 127,可通过 JVM 参数调整
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127); // 至少 127
h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
}
high = h;
// 创建缓存数组
cache = new Integer[(high - low) + 1];
int j = low;
for (int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
}
}
```
```drawio
```
```java
public class CacheDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 缓存范围内
// ═══════════════════════════════════════════════════════════════
Integer a = 127;
Integer b = 127;
System.out.println("a == b: " + (a == b)); // true
Integer c = -128;
Integer d = -128;
System.out.println("c == d: " + (c == d)); // true
// ═══════════════════════════════════════════════════════════════
// 超出缓存范围
// ═══════════════════════════════════════════════════════════════
Integer e = 128;
Integer f = 128;
System.out.println("e == f: " + (e == f)); // false
Integer g = -129;
Integer h = -129;
System.out.println("g == h: " + (g == h)); // false
// ═══════════════════════════════════════════════════════════════
// new 强制创建新对象(绕过缓存)
// ═══════════════════════════════════════════════════════════════
Integer i = new Integer(100); // 直接 new,不使用缓存
Integer j = Integer.valueOf(100); // 使用缓存
System.out.println("i == j: " + (i == j)); // false
// ⚠️ 从 JDK 9 开始,new Integer() 被标记为 @Deprecated
// 推荐使用 Integer.valueOf()
// ═══════════════════════════════════════════════════════════════
// Boolean 缓存
// ═══════════════════════════════════════════════════════════════
Boolean t1 = true;
Boolean t2 = Boolean.valueOf(true);
Boolean t3 = Boolean.TRUE;
System.out.println("t1 == t2: " + (t1 == t2)); // true
System.out.println("t1 == t3: " + (t1 == t3)); // true
}
}
// JVM 参数调整 Integer 缓存上限
// java -XX:AutoBoxCacheMax=1000 CacheDemo
```
### **7.5 装箱拆箱的性能影响**
```java
public class BoxingPerformanceDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 性能陷阱:频繁装箱拆箱
// ═══════════════════════════════════════════════════════════════
// ❌ 错误写法:Long 导致大量装箱
long startBad = System.currentTimeMillis();
Long sumBad = 0L; // 使用包装类型
for (long i = 0; i <= 1_000_000_000L; i++) {
sumBad += i; // 每次都要拆箱、相加、装箱
}
long endBad = System.currentTimeMillis();
System.out.println("包装类型耗时: " + (endBad - startBad) + "ms");
// ✅ 正确写法:使用基本类型
long startGood = System.currentTimeMillis();
long sumGood = 0L; // 使用基本类型
for (long i = 0; i <= 1_000_000_000L; i++) {
sumGood += i; // 纯基本类型运算
}
long endGood = System.currentTimeMillis();
System.out.println("基本类型耗时: " + (endGood - startGood) + "ms");
// 结果对比(示例):
// 包装类型耗时: 约 6000ms
// 基本类型耗时: 约 600ms
// 性能差 10 倍!
}
}
```
```drawio
```
---
## 八、BigDecimal 精确计算
### **8.1 为什么需要 BigDecimal**
```java
public class WhyBigDecimalDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 浮点数不适合金融计算
// ═══════════════════════════════════════════════════════════════
double price = 0.1;
double quantity = 0.2;
double total = price + quantity;
System.out.println("0.1 + 0.2 = " + total);
// 输出: 0.30000000000000004
// 如果这是钱...
double money = 1.0 - 0.9;
System.out.println("1.0 - 0.9 = " + money);
// 输出: 0.09999999999999998
// 累计误差
double sum = 0;
for (int i = 0; i < 10; i++) {
sum += 0.1;
}
System.out.println("0.1 × 10 = " + sum);
// 输出: 0.9999999999999999
}
}
```
### **8.2 BigDecimal 基本用法**
```java
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalBasicDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 创建 BigDecimal(推荐使用 String 构造器)
// ═══════════════════════════════════════════════════════════════
// ✅ 推荐:String 构造器,精确
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
// ❌ 不推荐:double 构造器,已经有精度问题
BigDecimal bad = new BigDecimal(0.1);
System.out.println("String构造: " + a); // 0.1
System.out.println("Double构造: " + bad); // 0.1000000000000000055511151231257827021181...
// ✅ 或使用 valueOf(内部转为 String)
BigDecimal c = BigDecimal.valueOf(0.1);
// ═══════════════════════════════════════════════════════════════
// 四则运算
// ═══════════════════════════════════════════════════════════════
BigDecimal x = new BigDecimal("10");
BigDecimal y = new BigDecimal("3");
System.out.println("加法: " + x.add(y)); // 13
System.out.println("减法: " + x.subtract(y)); // 7
System.out.println("乘法: " + x.multiply(y)); // 30
// 除法必须指定精度,否则除不尽会抛异常
// System.out.println(x.divide(y)); // ❌ ArithmeticException
System.out.println("除法: " + x.divide(y, 2, RoundingMode.HALF_UP)); // 3.33
// ═══════════════════════════════════════════════════════════════
// 精度和舍入模式
// ═══════════════════════════════════════════════════════════════
BigDecimal value = new BigDecimal("3.1415926");
// 保留 2 位小数,四舍五入
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP);
System.out.println("四舍五入: " + rounded); // 3.14
// 向上取整
System.out.println("向上取整: " + value.setScale(2, RoundingMode.UP)); // 3.15
// 向下取整
System.out.println("向下取整: " + value.setScale(2, RoundingMode.DOWN)); // 3.14
// 银行家舍入(四舍六入五成双)
System.out.println("银行家舍入: " + new BigDecimal("2.5").setScale(0, RoundingMode.HALF_EVEN)); // 2
System.out.println("银行家舍入: " + new BigDecimal("3.5").setScale(0, RoundingMode.HALF_EVEN)); // 4
}
}
```
### **8.3 舍入模式详解**
```drawio
```
### **8.4 BigDecimal 比较**
```java
public class BigDecimalCompareDemo {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1.00");
// ═══════════════════════════════════════════════════════════════
// equals() 比较值和精度(标度)
// ═══════════════════════════════════════════════════════════════
System.out.println("a.equals(b): " + a.equals(b)); // false!
// 因为 1.0 的标度是 1,1.00 的标度是 2
// ═══════════════════════════════════════════════════════════════
// compareTo() 只比较数值大小(推荐)
// ═══════════════════════════════════════════════════════════════
System.out.println("a.compareTo(b): " + a.compareTo(b)); // 0
// 0 表示相等,正数表示 a > b,负数表示 a < b
// 正确的相等判断
if (a.compareTo(b) == 0) {
System.out.println("a 和 b 数值相等");
}
// ═══════════════════════════════════════════════════════════════
// 使用 stripTrailingZeros() 去除尾部零后比较
// ═══════════════════════════════════════════════════════════════
BigDecimal c = new BigDecimal("1.0").stripTrailingZeros();
BigDecimal d = new BigDecimal("1.00").stripTrailingZeros();
System.out.println("stripTrailingZeros后 equals: " + c.equals(d)); // true
}
}
```
```drawio
```
### **8.5 工具类封装**
```java
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* BigDecimal 计算工具类
*/
public final class BigDecimalUtil {
// 默认精度
private static final int DEFAULT_SCALE = 2;
// 默认舍入模式
private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_UP;
private BigDecimalUtil() {}
/**
* 加法
*/
public static BigDecimal add(double v1, double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.add(b2);
}
/**
* 减法
*/
public static BigDecimal subtract(double v1, double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.subtract(b2);
}
/**
* 乘法
*/
public static BigDecimal multiply(double v1, double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.multiply(b2);
}
/**
* 除法(使用默认精度和舍入模式)
*/
public static BigDecimal divide(double v1, double v2) {
return divide(v1, v2, DEFAULT_SCALE, DEFAULT_ROUNDING);
}
/**
* 除法(指定精度和舍入模式)
*/
public static BigDecimal divide(double v1, double v2, int scale, RoundingMode mode) {
if (scale < 0) {
throw new IllegalArgumentException("精度不能为负数");
}
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.divide(b2, scale, mode);
}
/**
* 四舍五入
*/
public static BigDecimal round(double v, int scale) {
return BigDecimal.valueOf(v).setScale(scale, DEFAULT_ROUNDING);
}
/**
* 比较大小
* @return 正数: v1 > v2, 0: v1 == v2, 负数: v1 < v2
*/
public static int compare(double v1, double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.compareTo(b2);
}
}
```
---
## 九、BigInteger 大整数
### **9.1 为什么需要 BigInteger**
```java
public class WhyBigIntegerDemo {
public static void main(String[] args) {
// long 的最大值
long maxLong = Long.MAX_VALUE; // 9223372036854775807
System.out.println("Long.MAX_VALUE = " + maxLong);
// 溢出
System.out.println("Long.MAX_VALUE + 1 = " + (maxLong + 1)); // 负数!
// BigInteger 可以表示任意大小的整数
BigInteger big = new BigInteger("9223372036854775808"); // Long.MAX_VALUE + 1
System.out.println("BigInteger = " + big);
// 更大的数
BigInteger huge = new BigInteger("123456789012345678901234567890");
System.out.println("Huge = " + huge);
}
}
```
### **9.2 BigInteger 基本用法**
```java
import java.math.BigInteger;
public class BigIntegerDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 创建 BigInteger
// ═══════════════════════════════════════════════════════════════
BigInteger a = new BigInteger("12345678901234567890");
BigInteger b = BigInteger.valueOf(100L); // 从 long 创建
BigInteger c = BigInteger.TEN; // 常量
BigInteger d = BigInteger.ZERO;
BigInteger e = BigInteger.ONE;
// ═══════════════════════════════════════════════════════════════
// 四则运算
// ═══════════════════════════════════════════════════════════════
BigInteger x = new BigInteger("1000000000000");
BigInteger y = new BigInteger("999999999999");
System.out.println("加法: " + x.add(y));
System.out.println("减法: " + x.subtract(y));
System.out.println("乘法: " + x.multiply(y));
System.out.println("除法: " + x.divide(y));
System.out.println("取余: " + x.remainder(y));
System.out.println("幂运算: " + x.pow(2));
// 同时获取商和余数
BigInteger[] divideAndRemainder = x.divideAndRemainder(y);
System.out.println("商: " + divideAndRemainder[0]);
System.out.println("余数: " + divideAndRemainder[1]);
// ═══════════════════════════════════════════════════════════════
// 位运算
// ═══════════════════════════════════════════════════════════════
BigInteger num = new BigInteger("100");
System.out.println("左移2位: " + num.shiftLeft(2)); // 400
System.out.println("右移2位: " + num.shiftRight(2)); // 25
System.out.println("按位与: " + num.and(new BigInteger("50")));
System.out.println("按位或: " + num.or(new BigInteger("50")));
// ═══════════════════════════════════════════════════════════════
// 比较
// ═══════════════════════════════════════════════════════════════
System.out.println("compareTo: " + x.compareTo(y)); // 正数表示 x > y
System.out.println("equals: " + x.equals(y));
// ═══════════════════════════════════════════════════════════════
// 类型转换
// ═══════════════════════════════════════════════════════════════
BigInteger small = new BigInteger("100");
int intValue = small.intValue(); // 转为 int(可能溢出)
long longValue = small.longValue(); // 转为 long(可能溢出)
// 安全转换(溢出时抛出 ArithmeticException)
int safeInt = small.intValueExact();
long safeLong = small.longValueExact();
}
}
```
### **9.3 BigInteger 内部原理**
```drawio
```
---
## 十、总结
```drawio
```