基本类型(primitive) 引用类型(reference)
┌─────────────┐ ┌─────────────┐
│ 变量 = 值本身 │ │ 变量 = 对象的「遥控器」│
│ 存在栈上/直接 │ │ 变量存地址,对象在堆上 │
│ 不可能为 null │ │ 可能为 null(没遥控器)│
└─────────────┘ └─────────────┘
int a = 10; String s = "hi";
int b = a; b 复制值 10 String t = s; t 复制的是地址
改 b 不影响 a s 和 t 指向同一个对象
8 大基本类型全家福:
类型
字节
范围/说明
后端常用场景
byte
1
-128 ~ 127
二进制数据处理
short
2
±3.2 万
少用,省内存的旧字段
int
4
±21 亿
普通计数、状态码
long
8
±922 亿亿
数据库主键、雪花 ID
float
4
约 7 位有效数字
基本不用
double
8
约 15 位有效数字
科学计算;金额禁用
char
2
一个 Unicode 字符
单字符处理
boolean
—
true / false
开关、标志位
跟着做
步骤 1:声明各类型变量并打印
新建 TypeDemo.java:
public class TypeDemo {
public static void main(String[] args) {
int viewCount = 1024; // int 字面量直接写
long userId = 20261006123456789L; // long 字面量必须带 L 后缀!
double rating = 9.5; // 小数字面量默认是 double
float price = 19.9F; // float 字面量必须带 F 后缀
boolean vip = true;
char grade = 'A'; // char 用单引号,只装一个字符
byte level = 3;
System.out.printf("浏览 %d, 用户 %d, 评分 %.1f, 价格 %.2f, VIP %b, 等级 %c%n",
viewCount, userId, rating, price, vip, grade);
}
}
public class CastDemo {
public static void main(String[] args) {
// 自动提升:小容器倒进大容器,安全
int i = 100;
long l = i; // int -> long 自动完成
double d = l; // long -> double 自动完成
System.out.println(d); // 100.0
// 强制转换:大容器倒小容器,可能溢出/丢精度
long bigId = 3_000_000_000L; // 30 亿,超出 int 范围
int truncated = (int) bigId; // 必须写 (int),且结果已失真
System.out.println(truncated); // -1294967296,溢出成负数!
int score = (int) 99.9; // 浮点转整数直接砍掉小数(不是四舍五入)
System.out.println(score); // 99
}
}
步骤 3:体验浮点精度陷阱(金额问题的根源)
public class FloatTrap {
public static void main(String[] args) {
System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(0.1 + 0.2 == 0.3); // false!
// 正确姿势:金额用 BigDecimal,且必须用字符串构造
java.math.BigDecimal a = new java.math.BigDecimal("0.1");
java.math.BigDecimal b = new java.math.BigDecimal("0.2");
System.out.println(a.add(b)); // 0.3
// 注意:new BigDecimal(0.1)(传 double)照样有精度问题,务必传字符串
}
}
public class WrapperDemo {
public static void main(String[] args) {
Integer boxed = 100; // 自动装箱:int -> Integer
int unboxed = boxed; // 自动拆箱:Integer -> int
// 为什么要包装类?因为泛型集合只能装对象(第 9 课),
// 数据库字段允许 NULL 时,int 表示不了 null 而 Integer 可以。
Integer dbAge = null; // 模拟数据库 age 列为 NULL
int age = dbAge; // 运行时炸了:NullPointerException!
// 经典缓存陷阱
Integer x = 127, y = 127;
System.out.println(x == y); // true:走 IntegerCache 缓存,同一个对象
Integer m = 128, n = 128;
System.out.println(m == n); // false:超出缓存,两个新对象
System.out.println(m.equals(n)); // true:比较内容必须用 equals
}
}
步骤 5:var 与常量(JDK 10+)
public class VarDemo {
public static void main(String[] args) {
var message = "类型推断"; // 编译器推断为 String,仍是强类型
var numbers = new int[]{1, 2, 3};
System.out.println(message + numbers.length);
final int MAX_USERS = 1000; // final:只能赋值一次,即常量
System.out.println(MAX_USERS);
}
}
var 只能用于局部变量,不能用于字段、参数、返回值。类型还是要明确的,只是让编译器替你写。
讲清楚要点
基本类型存值,引用类型存地址:= 赋值时,基本类型复制值,引用类型复制地址。这是「改了 b 为何 a 也变」类 bug 的根源。
整数默认 int、小数默认 double:所以 long 字面量加 L、float 加 F。反过来(大转小)必须显式强制转换。