Java 基础语法深度拆解:变量、类型系统与表达式计算
大约 5 分钟
Java 基础语法深度拆解:变量、类型系统与表达式计算
我们从运行时内存视角与语言规范出发,深入到数值表示、比较语义与表达式计算细则,帮你在业务开发和面试场景都拿到“够用且正确”的认知。
新手先看 · 一屏速览
- 值类型存“值”,引用类型存“地址”;
==比较地址,equals比较语义 - 表达式里小类型会提升到大类型:
byte/short/char → int → long → float → double - “钱用 BigDecimal”,浮点别算钱;字符串按 code point 遍历避免“表情字符”坑
白话类比:杯子与箱子
- 基本类型像“杯子里的一杯水”,变量里直接就是那个值
- 引用类型像“快递单上的地址”,变量里是地址,真正的对象在“堆”上
把地址复制给形参,就是“地址的复印件”,你改箱子里的东西能被外面看到,但把复印件改成另一个地址,外面还是老地址。
1. Java 的两大类型世界
- 基本类型(值类型):byte、short、int、long、float、double、char、boolean
- 引用类型:类、接口、数组、枚举、记录(record)等
- 关键差异
- 内存位置:基本类型一般直接存放在栈帧或对象内存中;引用类型变量持有对象地址(引用)
- 比较方式:基本类型比较值,引用类型
==比较地址,equals比较语义 - 默认值:字段存在默认值(如 int 为 0),局部变量必须显式初始化
2. 数值类型与提升规则
表达式求值时,Java 会对低精度数值做隐式“数值提升”(Numeric Promotion):
byte/short/char参与运算先提升为int- 有
long/float/double时按照精度向上提升,最终与最高精度一致
short s = 1;
var x = s + 1; // int
long L = 1L; float f = 1.0f;
var y = L + f; // float
double d = 1.0; int i = 2;
var z = d + i; // double强制转换可能丢失精度或溢出:
int a = 130;
byte b = (byte) a; // -126 溢出(低 8 位截断)3. 整数、浮点与钱的故事
- 整数运算溢出是“未定义行为”?在 Java 中是“有定义的环绕”:
int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // -2147483648- 浮点采用 IEEE 754,存在二进制小数无法精确表示的误差:
System.out.println(0.1 + 0.2); // 0.30000000000000004- 金额计算请使用 BigDecimal:
BigDecimal x1 = new BigDecimal("0.1");
BigDecimal x2 = new BigDecimal("0.2");
System.out.println(x1.add(x2)); // 0.3## 4. 字符与编码:char、String 与 UTF-16
- `char` 是 UTF-16 代码单元(16 位),并不等价于完整 Unicode 字符
- 表情/部分汉字超出 BMP,会使用代理对(两个 `char`)
```java
String s = "A𝄞"; // 音乐符号 U+1D11E
System.out.println(s.length()); // 3("A" + 代理对两个 char)
System.out.println(s.codePointCount(0, s.length())); // 2 个 code point- 正确遍历字符应按 code point:
for (int cp : s.codePoints().toArray()) {
System.out.println(Integer.toHexString(cp));
}5. 比较语义:==、equals 与 hashCode
最近建一些几十个工作内推群,各大城市都有,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。 欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。

- 基本类型:
==比较值 - 引用类型:
==比较引用地址,equals可自定义“值相等”语义
String a1 = new String("abc");
String a2 = new String("abc");
System.out.println(a1 == a2); // false
System.out.println(a1.equals(a2)); // true- 覆盖 equals 时必须保持自反性/传递性/对称性,并同步覆盖 hashCode(集合键正确性)
6. 装箱与拆箱:Integer 的陷阱
自动装箱会将基本类型包裹为对象,存在缓存与空指针风险:
Integer i1 = 127, i2 = 127;
System.out.println(i1 == i2); // true(缓存)
Integer j1 = 128, j2 = 128;
System.out.println(j1 == j2); // false(超出缓存范围)
Integer n = null;
// int m = n; // NPE:自动拆箱时触发7. 运算符与优先级:短路与拼接
- 算术:
+ - * / %(整数除法会截断) - 逻辑:
&& || !(短路求值,避免无谓计算) - 位运算:
& | ^ ~ << >> >>>(>>>为无符号右移) - 字符串拼接从左到右:
System.out.println(1 + 2 + "A" + 3 + 4); // 3A34- 建议用括号明确优先级,复杂表达式重构为中间变量提高可读性
8. 实战清单:写对“看似简单”的代码
- 统一金额计算为 BigDecimal,禁止使用 float/double 存钱
- Map/Set 的键使用不可变对象并覆盖 equals/hashCode
- 谨慎使用自增自减混合表达式,优先写成多行中间变量
- 任何可能出现 null 的包装类型拆箱前先判空或使用 Optional
9. 练习与思考题
- 写一个
max(int... nums)基于流 API 实现,并比较与 for 循环的性能差异 - 实现
toHex(int n)返回补码十六进制字符串,解释负数表示 - 统计字符串中实际 Unicode 码点个数与每类字符数量(字母/数字/汉字/表情)
- 设计一个 Money 类,内部用 BigDecimal 表示,完成加减乘除与舍入策略,确保不可变与线程安全
参考答案(节选)
max(int... nums):Arrays.stream(nums).max().orElseThrow()。注意空数组与溢出风险。toHex(int n):使用Integer.toHexString(n);思考二进制补码与>>>无符号右移的语义。- 统计 Unicode:
s.codePoints()流式遍历,使用Character.UnicodeBlock分类;注意代理对。 - Money:内部 BigDecimal、不可变类、统一舍入策略(如 HALF_UP)、货币与精度由构造时确定。
