写了几年 Java 的人,也未必能答对这两题:
csharp
System.out.println(0.1 + 0.2 == 0.3); // ?
System.out.println(Integer.MAX_VALUE + 1); // ?
答案分别是 false 和 -2147483648。
第一个是浮点精度问题,第二个是整数溢出。这两个坑的根源都在基本数据类型。今天就系统过一遍 Java 的 8 种基本类型、数组操作和最容易翻车的细节。
变量分四种,别搞混
Java 的变量按"在哪声明、归谁管"分为四种:
| 类型 | 声明位置 | 有默认值? | 生命周期 |
|---|---|---|---|
| 实例变量 | 类体内,无 static | 有 | 对象存在期间 |
| 类变量 | 类体内,有 static | 有 | 类加载到卸载 |
| 局部变量 | 方法体内 | 无 | 方法执行期间 |
| 参数 | 方法签名 | 调用者传入 | 方法执行期间 |
记住一个点就够了:局部变量没有默认值,用之前必须初始化,否则编译报错。
8 种基本类型速查
整数家族
csharp
byte (1B) → short (2B) → int (4B) → long (8B)
-128~127 -3万~3万 ±21亿 ±922亿亿
90% 的场景用 int。超 21 亿用 long(记得加 L)。byte/short 只在大数组省内存时考虑。
浮点家族
| 类型 | 精度 | 使用场景 |
|---|---|---|
float (4B) |
~7 位 | 大数组、图形(加 f) |
double (8B) |
~15 位 | 默认选择 |
BigDecimal |
任意 | 算钱必须用 |
其他
boolean:true/false,大小未精确定义char:16 位 Unicode,本质是无符号整数
String 不是基本类型 ,是 java.lang.String 引用类型。
6 个必踩的坑
坑 1:浮点不可信
csharp
System.out.println(0.1 + 0.2); // 0.30000000000000004
原因:0.1 在二进制中是无限循环小数。
修复:算钱用 BigDecimal,必须字符串构造。
java
BigDecimal total = new BigDecimal("19.99").multiply(new BigDecimal("3"));
// 59.97 精确
new BigDecimal(0.1) 等于把 double 的误差带进去,白搭。
坑 2:整数溢出是哑巴
arduino
int max = Integer.MAX_VALUE;
System.out.println(max + 1); // -2147483648,没有任何报错
修复:用 Math.addExact,溢出时抛 ArithmeticException。
坑 3:float f = 3.14; 编译不过
3.14 默认是 double,赋给 float 是窄化。写成 3.14f。
同理 long n = 10000000000; 也不行------字面量超 int 范围,要加 L。
坑 4:byte 加 byte 变 int
ini
byte a = 50, b = 60;
// byte c = a + b; // ❌ 编译错误!结果是 int
int c = a + b; // ✅
Java 中 byte/short/char 运算自动提升为 int。
坑 5:打印数组输出地址
ini
int[] arr = {1, 2, 3};
System.out.println(arr); // [I@6d06d69c
System.out.println(Arrays.toString(arr)); // [1, 2, 3]
坑 6:== 比较数组比的是引用
ini
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(a == b); // false
System.out.println(Arrays.equals(a, b)); // true
数组核心操作
数组是固定长度的同类型容器,索引从 0 开始。
ini
// 两种创建方式
int[] nums = new int[5];
int[] nums2 = {10, 20, 30, 40, 50};
java.util.Arrays 工具类全家桶:
| 操作 | 方法 | 注意 |
|---|---|---|
| 排序 | Arrays.sort(arr) |
原地修改 |
| 搜索 | Arrays.binarySearch(arr, key) |
必须先排序 |
| 比较 | Arrays.equals(a, b) |
比内容不比地址 |
| 填充 | Arrays.fill(arr, val) |
--- |
| 复制 | Arrays.copyOfRange(arr, 2, 5) |
[from, to) |
| 转字符串 | Arrays.toString(arr) |
调试必备 |
多维数组是"数组的数组",每行长度可以不同:
ini
int[][] matrix = {
{1, 2, 3},
{4, 5} // 第二行只有 2 个元素,合法
};
类型转换规则
自动拓宽 (小→大,安全):byte → short → int → long → float → double
强制窄化(大→小,可能丢数据):
ini
double pi = 3.99;
int n = (int) pi; // 3,截断不是四舍五入!
int big = 130;
byte b = (byte) big; // -126,溢出
面试快问快答
| 问题 | 答案 |
|---|---|
| Java 几种基本类型? | 8 种,String 不是 |
| boolean 占几字节? | JLS 未定义,JVM 通常 4 字节 |
| 局部变量有默认值? | 没有,必须初始化 |
| 数组长度能改吗? | 不能,要"扩容"用 ArrayList |
| float 和 double 能算钱吗? | 不能,用 BigDecimal |
| char 能存中文吗? | BMP 范围内的可以 |
这些基础看似简单,但浮点精度、整数溢出、类型提升这些坑在生产环境里真能造成事故。打好地基比什么都重要。
作者:IT探险家 | 更多 Java 深度内容见主页