01.1 — 数据类型与运算符
定位: 一切 Java 程序的类型基石 — 8种基本类型的设计动机与使用规则 面试高频度: ⭐⭐⭐⭐ 考查方式: 类型取值范围、自动/强制类型转换、float/double 精度陷阱
一、这是什么?为什么需要它?
是什么
Java 有 8 种基本类型(primitive type),分为四组:
| 组别 | 类型 | 内存 | 默认值 |
|---|---|---|---|
| 整数 | byte | 8 bit | 0 |
| short | 16 bit | 0 | |
| int | 32 bit | 0 | |
| long | 64 bit | 0L | |
| 浮点 | float | 32 bit | 0.0f |
| double | 64 bit | 0.0d | |
| 字符 | char | 16 bit | 空字符 |
| 布尔 | boolean | ~8 bit JVM依赖 | false |
为什么需要它们?
没有基本类型会怎样?
如果只有 Object,每个 int 值都需要 new Integer() 包装:
- 内存暴涨 3-5 倍(对象头 + 实例数据 + 对齐)
- 性能下降(堆分配 + GC)
- 无法直接映射到 CPU 寄存器操作
所以:基本类型是 Java 与硬件之间的桥梁,直接对应 CPU 的寄存器和 ALU 操作。
┌─────────────────────────────────────────────────────────────┐
│ Java 类型系统:基本类型 vs 引用类型 │
│ │
│ 基本类型: │
│ int a = 10; → 栈上直接存值 [10] │
│ │
│ 引用类型: │
│ Integer b = new Integer(10); │
│ 栈 堆 │
│ [引用] ──────────→ [Integer 对象: value=10] │
│ │
│ 结论:基本类型 = 直接操作值,引用类型 = 间接操作对象 │
└─────────────────────────────────────────────────────────────┘二、原理拆解
2.1 整型设计——为什么是这 4 种?
byte (8) : 最小存储单位 — 文件流、网络协议
short (16) : 兼容 16 位系统 legacy
int (32) : 默认整数类型 — CPU 32/64 位效率最高
long (64) : 需要大范围时(时间戳、ID)为什么 int 是默认整数类型?
java
byte b = 100; // OK
byte c = 200; // 编译错误:int 不能隐式转 byte
int d = 100; // 最自然
long e = 100L; // 需要 L 后缀为什么 long 需要 L 后缀? 因为 100 字面量是 int 类型,int → long 是隐式转换(安全),显式用 L 告诉编译器 + 读者"这个数可能超出 int 范围"。
2.2 浮点设计——float/double 为什么不精确?
java
0.1 + 0.2 // 0.30000000000000004 (不是 0.3!)原因:IEEE 754 二进制无法精确表示某些十进制小数。
十进制 0.1 = 二进制 0.00011001100110011... (无限循环)
↓
float/double 只能存有限位 → 截断 → 精度损失解决方案:精确计算用 BigDecimal(String 构造器!)
java
// ✅ 正确
new BigDecimal("0.1").add(new BigDecimal("0.2"));
// ❌ 错误(double 构造器仍然有精度问题)
new BigDecimal(0.1).add(new BigDecimal(0.2));2.3 类型转换规则
自动转换(小→大,安全): byte → short → int → long → float → double
↑
char (unsigned)
强制转换(大→小,可能溢出):double → float → long → int → short → byte自动转换的动机:不丢失信息的转换,编译器自动做。
强制转换的陷阱:
java
int big = 300;
byte small = (byte) big; // 300 % 256 = 44
// 溢出原理:
// int 300 = 00000000 00000000 00000001 00101100
// byte 截断低8位 = 00101100 = 44┌─────────────────────────────────────────────────────────────┐
│ 类型转换方向图 │
│ │
│ double │
│ ↑ ↑ │
│ float long │
│ ↑ ↑ │
│ int ←── char (无符号特殊) │
│ ↑ │
│ short │
│ ↑ │
│ byte │
│ │
│ 自动:箭头方向 (小→大) 强制:反方向 (大→小,可能丢失) │
└─────────────────────────────────────────────────────────────┘三、图解全景
┌─────────────────────────────────────────────────────────────┐
│ Java 运算的隐式类型提升 │
│ │
│ 表达式中的自动提升规则: │
│ │
│ byte/short/char → int (最小精度) │
│ │
│ 例: │
│ byte a = 10, b = 20; │
│ int c = a + b; // a+b 先提升为 int │
│ byte d = a + b; // ❌ 编译错误:int 不能隐式转 byte │
│ │
│ 结合性 & 优先级: │
│ │
│ int x = 1 + 2 * 3; // 7 (乘优先于加) │
│ int y = (1 + 2) * 3; // 9 (括号改变优先级) │
│ int z = 1 + 2 + "3"; // "33" (String 拼接优先) │
└─────────────────────────────────────────────────────────────┘四、实战验证
4.1 各类型取值范围验证
java
// byte 范围
System.out.println(Byte.MIN_VALUE + " ~ " + Byte.MAX_VALUE);
// -128 ~ 127
// int 溢出观察
int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // -2147483648 (回绕)
// float 精度损失
System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(1.0f - 0.9f); // 0.1000000244.2 类型转换验证
java
// 自动转换
int i = 100;
long l = i; // OK:int → long 自动
float f = l; // OK:long → float 自动(可能有精度损失)
System.out.println(l == (long)f); // false! long 转 float 可能丢精度
// 强制转换
int big = 256;
byte small = (byte) big;
System.out.println(small); // 0
// 复合赋值陷阱
int x = 10;
x += 3.5; // 隐含强制转换: x = (int)(10 + 3.5) = 13五、面试视角
| 追问 | 答案要点 |
|---|---|
| float 和 double 的区别? | 精度:float 7位,double 15位;内存:32 vs 64;默认浮点字面量是 double |
| 为什么 long 转 float 可能有精度损失? | long 63位尾数 > float 23位尾数,高位截断 |
| switch 支持哪些类型?演进过程 | byte/short/char/int (JDK5) → enum (JDK5) → String (JDK7) |
| i++ 和 ++i 的区别? | i++ 先取值后自增;++i 先自增后赋值;底层字节码不同 |
| & 和 && 的区别? | & 位运算/逻辑与(不短路);&& 短路与(左边 false 不计算右边) |
📚 相关链接
- **String深度解析** — String 相关的类型转换
- **Object类与通用方法** — Object 类中的通用方法
- **包装类详解** — 包装类与基本类型的互转
- ← 返回 **语言基础索引**