Skip to content

变量与类型:数据的容器

难度:初级 | 预计时间:40 分钟 | 前置:Hello World


📖 购物车的烦恼

故事背景

你接到一个需求:写一个购物车结算功能。商品价格是 19.9、数量是 3、用户余额是 100.00、是否包邮需要判断。你用 JS 写的时候,统统 let 就完事了。但 Java 里不行——价格是小数、数量是整数,它们是不同的类型。如果你全用字符串存,计算时就会翻车。这节课让你掌握 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 类,包含 celsiusToFahrenheitfahrenheitToCelsius 两个方法。注意类型选择。

<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 / count100.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 / b5.0 / 2

</details>