变量与类型:数据的容器
难度:初级 | 预计时间:40 分钟 | 前置:Hello World
📖 购物车的烦恼
故事背景
你接到一个需求:写一个购物车结算功能。商品价格是 19.9、数量是 3、用户余额是 100.00、是否包邮需要判断。你用 JS 写的时候,统统 let 就完事了。但 Java 里不行——价格是小数、数量是整数,它们是不同的类型。如果你全用字符串存,计算时就会翻车。这节课让你掌握 Java 的类型系统,它是写 Java 时每时每刻都在用的底层语言。
💻 代码演示
看一个简单的购物车计算,重点关注变量声明的类型:
// ShoppingCart.java — 变量与类型演示
import java.math.BigDecimal;
public class ShoppingCart {
public static void main(String[] args) {
// 基本类型 — 直接存值
int quantity = 3; // 整数
double price = 19.9; // 浮点数(有精度问题!)
boolean freeShipping = false; // 布尔
char currency = '¥'; // 字符
// 引用类型 — 存的是"地址"
String itemName = "机械键盘"; // 字符串(引用类型)
BigDecimal safePrice = new BigDecimal("19.90"); // 精确小数
// 问题演示:浮点数精度
double total1 = price * quantity;
System.out.println("double 计算: " + price + " × " + quantity + " = " + total1);
// 正确做法:BigDecimal
BigDecimal total2 = safePrice.multiply(new BigDecimal(quantity));
System.out.println("BigDecimal 计算: " + safePrice + " × " + quantity + " = " + total2);
// 整数除法陷阱
int a = 5, b = 2;
System.out.println("5 / 2 = " + (a / b)); // 输出 2,不是 2.5!
}
}运行输出:
double 计算: 19.9 × 3 = 59.699999999999996
BigDecimal 计算: 19.90 × 3 = 59.70
5 / 2 = 2🎯 三个核心问题
这是什么?
Java 有 8 种基本类型(primitive types):byte, short, int, long, float, double, boolean, char——它们直接存值,效率最高。
除此之外全是引用类型(reference types):String、数组、类实例等——变量里存的是对象在内存中的地址。
为什么需要它?
基本类型快、省内存,适合频繁计算的场景。引用类型灵活,可以拥有方法和属性。Java 这样设计为了在性能和表达力之间取平衡。
前端类比:基本类型 ≈ JS 的 number/boolean(栈上分配),引用类型 ≈ JS 的 Object/Array(堆上分配,变量存引用)。但 Java 更严格,你不能把一个 int 赋值给 String。
如果没有它会怎样?
如果 Java 没有类型系统(像 JS 那样弱类型),编译器无法在编译期发现错误——"hello" + 42 可能悄悄变成 "hello42" 而不是报错。类型系统让你在编码时就消灭一类 bug,而不是等上线后才发现。
📝 原理讲解
作为前端开发者,理解 Java 类型的关键区别:
基本类型 vs 引用类型的存储差异:基本类型变量直接存值(在栈上),赋值是复制值。引用类型变量存的是地址(在堆上),赋值是复制地址——两个变量指向同一个对象。
double精度问题:0.1 + 0.2 = 0.30000000000000004,这不是 Java 的 bug,而是 IEEE 754 浮点数标准的固有问题。涉及金额必须用BigDecimal。整数除法:两个
int相除结果仍是int(截断小数部分)。要想得到小数,至少把一个操作数转成double:(double) a / b。var关键字(Java 10+):类型显而易见时可以用var简化:var users = new ArrayList<User>();。编译器自动推断类型,不损失类型安全。
🎨 生活类比
类比理解
基本类型像量杯——刻度清晰、直接读取、精确但功能有限(int 只能装整数,就像量杯只能装液体)。 引用类型像带二维码的货箱——箱子上贴了标签(变量存标签),真正的货在仓库里(堆内存)。你递标签给别人,别人能拿到同一箱货。 BigDecimal 是精密天平——专门称贵重物品(金额),绝不马虎。double 是普通体重秤,够用但不精确。
✏️ 动手练习
练习 1
写一个 TemperatureConverter 类,包含 celsiusToFahrenheit 和 fahrenheitToCelsius 两个方法。注意类型选择。
<details> <summary>💡 查看提示</summary>
公式:F = C × 9/5 + 32。注意整数除法问题,用 9.0/5.0 或把变量转成 double。
</details>
练习 2
修复下面代码的 bug: int total = 100; int count = 3; double avg = total / count;avg 输出 33.0 而不是 33.333...,为什么?怎么修?
<details> <summary>💡 查看提示</summary>
total / count 先做整数除法得 33,再赋给 double。需要 (double) total / count 或 100.0 / 3。
</details>
练习 3
用 BigDecimal 计算商品:单价 2.35,买 3 件,会员打 8.8 折。输出最终价格(精确到分)。
<details> <summary>💡 查看提示</summary>
用 new BigDecimal("2.35") —— 注意用字符串构造器,不要用 double,否则精度问题会带进来。
</details>
✅ 自检站
<details> <summary><strong>Java 的基本类型有哪 8 种?String 是基本类型吗?</strong></summary>
8 种:byte, short, int, long, float, double, boolean, char。String 不是基本类型,它是引用类型(java.lang.String 类)。虽然它用起来像基本类型(可以直接用 "" 创建),但本质上是对象。
</details>
<details> <summary><strong>为什么金额计算不能用 double?应该用什么?</strong></summary>
double 使用 IEEE 754 二进制浮点数,无法精确表示十进制小数(0.1 在二进制中是无限循环小数)。金额计算需要精确到分,必须用 BigDecimal。BigDecimal 内部用整数来表示小数,天然精确。
</details>
<details> <summary><strong>int a = 5; int b = 2; System.out.println(a / b); 输出什么?为什么?</strong></summary>
输出 2,不是 2.5。因为两个 int 相除执行整数除法,结果截断小数部分。想要 2.5,需要 (double) a / b 或 5.0 / 2。
</details>