--- 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 ```