问题背景

Java 的 8 种基本数据类型是语言基础中的基础,但实际开发中的很多诡异 Bug 恰恰来源于对基本类型细节的忽视——浮点精度误差、整数静默溢出、类型自动提升等。本文整理了最常见的问题和对应的解决方案。

8 种基本类型一览

整数: byte(1B) → short(2B) → int(4B) → long(8B)
浮点: float(4B) → double(8B)
其他: boolean(?B)   char(2B)

选型原则:整数默认 int,超 21 亿用 long;小数默认 double,金额用 BigDecimal

问题 1:浮点运算不精确

现象

System.out.println(0.1 + 0.2);        // 0.30000000000000004
System.out.println(0.1 + 0.2 == 0.3); // false

原因

IEEE 754 标准下,0.1 在二进制中是无限循环小数,存储时被截断产生误差。

解决方案

方案 A:BigDecimal(推荐用于金额)

BigDecimal a = new BigDecimal("0.1"); // 必须用 String 构造
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b)); // 0.3

⚠️ new BigDecimal(0.1) 会引入 double 的误差,不要用。

方案 B:epsilon 比较(科学计算场景)

double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(Math.abs(a - b) < 1e-9); // true

方案 C:long 存分(电商常用)

long priceInCents = 1999; // 19.99 元 = 1999 分
long total = priceInCents * 3; // 5997 分 = 59.97 元

问题 2:整数溢出无异常

现象

int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // -2147483648
// 没有任何异常!

原因

Java 整数运算遵循二进制补码的环绕语义。溢出时高位截断,不抛异常。

解决方案

// Math.xxxExact 系列方法,溢出时抛 ArithmeticException
int result = Math.addExact(Integer.MAX_VALUE, 1); // 抛异常
int product = Math.multiplyExact(100000, 100000); // 抛异常

// 或提前用 long
long safe = (long) 100000 * 100000; // 10000000000L

问题 3:字面量类型不匹配

现象

float f = 3.14;           // ❌ 编译错误
long n = 10000000000;     // ❌ 编译错误

原因

  • 小数字面量默认是 double,赋给 float 是窄化
  • 整数字面量默认是 int,超 int 范围编译器不认

解决方案

float f = 3.14f;               // 加 f 后缀
long n = 10_000_000_000L;      // 加 L 后缀(推荐大写)

问题 4:byte/short 运算提升

现象

byte a = 50, b = 60;
byte c = a + b; // ❌ 编译错误:incompatible types

原因

JLS 规定 byteshortchar 参与算术运算时自动提升为 int

解决方案

int c = a + b;            // 用 int 接收
byte d = (byte)(a + b);   // 或强制转换(注意溢出风险)

问题 5:局部变量未初始化

现象

int x;
System.out.println(x); // ❌ 编译错误

原因

字段(实例变量/类变量)有默认值(数值 0,boolean false,引用 null),但局部变量没有。

解决方案

声明时或使用前赋值:

int x = 0;
System.out.println(x); // ✅

问题 6:数组打印和比较

现象

int[] a = {1, 2, 3};
System.out.println(a);       // [I@6d06d69c
System.out.println(a == b);  // false(即使内容相同)

解决方案

System.out.println(Arrays.toString(a));  // [1, 2, 3]
System.out.println(Arrays.equals(a, b)); // true

默认值速查

类型默认值类型默认值
byte0float0.0f
short0double0.0d
int0booleanfalse
long0Lchar'\u0000'
引用类型null

仅限字段。局部变量无默认值。

Arrays 工具类速查

import java.util.Arrays;

int[] arr = {5, 3, 8, 1};

Arrays.sort(arr);                            // 升序排序(原地)
Arrays.binarySearch(arr, 5);                 // 二分搜索(需已排序)
Arrays.equals(arr1, arr2);                   // 比较内容
Arrays.fill(arr, 0);                         // 填充
Arrays.copyOf(arr, 10);                      // 复制(可扩展)
Arrays.copyOfRange(arr, 1, 3);               // 子数组 [1,3)
Arrays.toString(arr);                        // 转字符串
Arrays.stream(arr).sum();                    // 转流操作

以上覆盖了 Java 基本数据类型最常见的 6 类问题。打好这个基础,后续学习面向对象、集合框架时会顺利很多。

作者:IT探险家

标签: none

添加新评论