TW

// post

Java 基础讲义:从零做出一个记账本,10 节课学透 Java 核心基础

这是一份可直接自学的 Java 基础讲义。用一个"个人记账本"小程序贯穿全程:从变量、类与对象、集合,到菜单交互、方法拆分、异常与文件存盘,共 10 节。每节都有知识点、可运行代码、常见坑和练习,边学边做,学完你能自己写出真正用得上的程序。

2026.10.14·26 min read·16 views

一套给零基础同学的「能翻、能练、能记住」的手册。 配套视频逐字稿与可运行源码见各节「配套」;完整版与答疑领取方式在文末。


写在前面:这本讲义怎么用

你可能听过一句话:人人都能学编程。但真去试的时候,常常卡在第一步——不是因为你笨,是因为传统学法把"地基、钢筋、水泥"先讲半年,却始终不让你看到楼长什么样。

我们这门课换一种学法,叫 案例贯穿 · 逆向拆解 · 螺旋递进:

  • 先看成品:每一阶段先让你看到一个能跑的东西,建立"这玩意儿我也能做"的信心;
  • 再倒着学:不从地基讲起,而是从成品里缺什么、补什么,学的每个知识点当场就知道用在哪儿;
  • 系统长大:同一个记账本,从控制台一点点长成完整全栈(后面 P2 加数据库、P3 加后端、P4 加网页)。

这本讲义的用法:

  1. 先粗读一节的目标,知道"学完能干什么";
  2. 跟着知识点和代码片段在电脑上敲一遍;
  3. 做"动手练习",做不出来再去翻"常见坑";
  4. 用"一句话记住"自检。

全套知识点地图

节主题你学完能做什么对应 demo
L0开胃:看成品看懂一个完整记账本长啥样AccountBook.java(终态)
L1变量与数据类型用变量存下一笔账并打印L1_Variables.java
L2类与对象用"类"把一笔账打包成模板,new 出对象L2_AccountClass.java
L3集合用 ArrayList 装很多笔账并遍历L3_Collection.java
L4流程控制+输入做出能反复操作的菜单(while/if/switch/Scanner)L4_Menu.java
L5方法拆分把功能抽成方法,main 只调度L5_Methods.java
L6字符串与格式化用 printf 把账目打印成对齐表格L6_Format.java
L7异常处理输错了也不崩(try-catch)L7_Exception.java
L8文件持久化关掉程序账还在(读写文件)L8_Persistence.java(终态见 AccountBook.java)
L9复盘+AI 协作用 AI 扩展功能,并读懂它生成的代码L9_AI_Extension.java

第 0 步:环境准备(只做一次)

  1. 安装 JDK 11 或更高版本(推荐 17)。装完在命令行输入 java -version,能看到版本号就成功了。

  2. 把讲义配套的 demo/ 文件夹下载到本地。

  3. 运行单文件 demo(JDK 11+ 支持直接跑单个 .java):

    cd demo/steps
    java L1_Variables.java
    

    如果 JDK 版本较旧,先编译再运行:javac L1_Variables.java && java L1_Variables。

配套:环境装不上、命令报错?这些是公开版之外的高频问题,完整版里有"从零装环境"录屏 + 一对一报错的入口,见文末。


L0 · 开胃:先看到你能做出的东西

本节能做什么:不写代码,先建立动机——你已经知道我们要做出一个能录入、查看、统计、存盘的记账本。

成品长什么样(运行 AccountBook.java):

  • 菜单:1.录入 2.查看 3.统计 4.保存 5.退出
  • 一笔账的字段:id / 类型(收入·支出) / 金额 / 分类 / 备注 / 日期
  • 统计:总收入、总支出、结余,以及每个分类花了多少
  • 保存:账本写入 accountbook.txt,关掉再开数据还在

为什么这样学:传统路线先讲语法半年,你不知道学来干嘛;我们反过来,先让你看到"楼",再一层层拆"砖"。后面每一节,都是往这个记账本上添一块砖。

一句话记住:先见楼,再搬砖;跟着做,你也能写出来。


L1 · 变量与数据类型 —— 存下第一笔钱

本节能做什么:用变量把"一笔账"的字段分别存起来,并把它打印出来。

知识点

  • 变量:给数据起个名字、存到内存里,以后用名字就能找到它。类比"带名字的盒子"。
  • 基本类型:double(小数,钱必须用这个)、int(整数)、boolean(真假)。
  • 引用类型:String(文字/字符串)。
  • 字面量:直接写出来的数据,如 "支出"、35.5、2026。
  • 打印:System.out.println("内容" + 变量),用 + 把文字和变量拼起来。

代码片段(L1_Variables.java 核心)

String type = "支出";      // 文字用 String
double amount = 35.5;      // 钱用 double(小数)
String category = "餐饮";
String note = "午饭";
int year = 2026;           // 整数用 int

System.out.println("金额:" + amount + " 元");

double budget = 100.0;
System.out.println("午饭占日预算:" + (amount / budget * 100) + "%"); // 变量能参与运算

常见坑

  • ❌ 把钱存成 int:35.5 会被丢掉小数变成 35,账就记错了。钱一律用 double。
  • ❌ 把 String 当数字运算:"35" + 1 得到 "351"(拼接),不是 36。需要数字就用 double/int。

动手练习:定义几个变量,记录一笔你今天的账(比如奶茶 18 元),把它打印出来。

一句话记住:变量是带名字的盒子;钱用 double,文字用 String,整数用 int。


L2 · 类与对象 —— 把一笔账变成模板

本节能做什么:用"类"把一笔账的字段打包成一个模板,每记一笔就 new 一个对象,不再用五六个零散变量。

知识点

  • 类(class):一张"记账模板",上面画好格子(字段)。代码里就是 Account。
  • 对象(object):按模板填出来的一张单子,new Account(...) 就是填一张。
  • 字段 + 构造器:字段是模板上的格子;构造器是"创建时一次性填好"的方法。
  • 封装(private + getter):字段写成 private,外面不能直接改,要看通过 getType() 这类 getter 方法。刚开始觉得麻烦,程序变复杂后你会感谢它。
  • this:区分"模板里的字段"和"传进来的参数",同名时用 this.xxx 指字段。

代码片段(L2_AccountClass.java 核心)

static class Account {
    private String type;
    private double amount;
    private String note;
    // 构造器:创建对象时一次性赋值
    public Account(String type, double amount, String note) {
        this.type = type; this.amount = amount; this.note = note;
    }
    // getter:封装后通过方法读字段
    public String getType() { return type; }
    public double getAmount() { return amount; }
}

// new 出两笔账(对象)
Account a1 = new Account("支出", 35.5, "午饭");
Account a2 = new Account("收入", 8000, "工资");
System.out.println(a1.getType() + " " + a1.getAmount());

常见坑

  • ❌ 直接 a1.type 访问私有字段会报错——记住用 getter(a1.getType())。
  • ❌ 构造器参数顺序和字段对不上,导致数据填错格子。

动手练习:给 Account 再加一个 category(分类)字段,写对应的构造器和 getter,再创建两笔不同的账打印出来。

一句话记住:类是模板,对象是按模板填的单子;private 字段用 getter 看。


L3 · 集合 —— 装下很多笔账

本节能做什么:用 ArrayList 把很多笔账攒到一起,并用循环把它们一条条列出来。

知识点

  • 为什么不用数组:数组长度固定,定好装 10 笔,第 11 笔就放不进,不灵活。
  • ArrayList(集合):会自动变长的"袋子",add(对象) 往里放,size() 看数量。
  • 泛型 <Account>:告诉集合"只装 Account 对象",避免混装、取出来还不用强转。
  • for-each 遍历:for (Account a : accounts) 把袋子里每笔账依次取出来。

代码片段(L3_Collection.java 核心)

List<Account> accounts = new ArrayList<>();
accounts.add(new Account("支出", 35.5, "午饭"));
accounts.add(new Account("支出", 12.0, "地铁"));
accounts.add(new Account("收入", 8000, "工资"));

for (Account a : accounts) {            // 遍历
    System.out.println(a.getType() + " " + a.getAmount() + " " + a.getNote());
}
System.out.println("共 " + accounts.size() + " 笔账");

常见坑

  • ❌ 用数组硬存导致"放不下"。记账笔数不确定,一律用 ArrayList。
  • ❌ 遍历时空指针:集合里混入了 null。本阶段保证只 add 真实对象即可。

动手练习:用集合存 5 笔账,遍历打印,并输出总共有几笔。

一句话记住:数组长度固定不灵活,装很多对象用 ArrayList;for-each 一条条取。


L4 · 流程控制 + 输入 —— 做成交互菜单

本节能做什么:让程序"能用起来"——你输入什么它就记什么,而不是把数据写死在代码里。

知识点

  • while 循环:while (true) 让菜单一直转,等你操作,直到你选退出。
  • if / else if / else:按条件走不同分支(也可用 switch,见 L5)。
  • switch:根据"选择"走对应分支,比一堆 if 更清晰。
  • Scanner:程序和键盘的桥梁,sc.nextLine() 读一行文字,Double.parseDouble(...) 把文字转成数字。
  • break:跳出循环(退出菜单)。

代码片段(L4_Menu.java 核心)

Scanner sc = new Scanner(System.in);
while (true) {                       // 一直转,直到退出
    System.out.println("\n1.录入  2.查看  0.退出");
    System.out.print("请选择:");
    String choice = sc.nextLine();
    if (choice.equals("1")) {
        System.out.print("金额:");
        double amount = Double.parseDouble(sc.nextLine()); // 文字→数字
        accounts.add(new Account("支出", amount, "午饭"));
    } else if (choice.equals("0")) {
        break;                       // 跳出循环
    }
}

常见坑

  • ❌ 忘了 break,选了退出还继续跑(if 写法)或贯穿到下一个 case(switch 写法)。
  • ❌ Double.parseDouble 收到非数字会崩——这个坑 L7 用异常解决。
  • ❌ 用 == 比较字符串(如 choice == "1"),字符串要用 .equals()。

动手练习:写出菜单骨架——显示 1 录入 / 2 查看 / 0 退出,用 while 包住、用 if 或 switch 分流,分支里先打印一句话占位。

一句话记住:while 让程序反复等指令;Scanner 读输入;比较字符串用 equals。


L5 · 方法拆分 —— 让 main 变干净

本节能做什么:把"录入""查看"各自抽成独立方法,main 只负责调度,代码不再一大坨。

知识点

  • 方法(method):一个个独立的小工具。录入是一把螺丝刀,查看是一把扳手。
  • 定义:static void add() 中 void 表示"不返回值";要返回结果就用具体类型(如 static int sum())。
  • 参数:传给方法的数据(如要录入的这笔账);返回值:方法跑完交给你的结果。
  • 调用:在 main 里写 add();、list(); 即可使用。
  • 代码组织:功能拆开,改"查看"直接找查看方法,不用全篇翻。

代码片段(L5_Methods.java 核心)

static void add() {                  // 录入方法(无返回值用 void)
    System.out.print("金额:");
    double amount = Double.parseDouble(sc.nextLine());
    accounts.add(new Account("支出", amount, "午饭"));
    System.out.println("录入成功!");
}
static void list() {                 // 查看方法
    for (Account a : accounts) System.out.println(a.getType()+" "+a.getAmount());
}

public static void main(String[] args) {
    while (true) {
        String choice = sc.nextLine();
        switch (choice) {
            case "1": add(); break;  // 调用方法
            case "2": list(); break;
            case "0": return;
        }
    }
}

常见坑

  • ❌ 把全部逻辑堆在 main,导致几百行挤一起、难读难改。
  • ❌ 方法需要返回结果却写成 void,拿不到值。

动手练习:把上节课的菜单骨架里三个占位分支,各补成一个真正的方法(录入/查看/退出),main 只做调用。

一句话记住:方法是独立小工具;void 不返回,要返回就写类型;main 只调度。


L6 · 字符串与格式化 —— 账目更好看

本节能做什么:把杂乱的输出排成对齐的表格,金额统一两位小数、日期规整。

知识点

  • String 常用:拼接(+)、isEmpty() 判断空、equals() 比较。
  • printf 格式化输出:规定宽度与小数位,让数字像列队一样对齐。
    • %-6s:左对齐、占 6 格的字符串
    • %-10.2f:左对齐、占 10 格、保留 2 位小数的小数
    • %n:换行(跨平台)
  • LocalDate.now():取当前日期,配合 DateTimeFormatter 格式化成 yyyy-MM-dd。

代码片段(L6_Format.java 核心)

System.out.printf("%-6s %-10s %-12s %s%n", "类型", "金额", "日期", "备注");
for (Account a : accounts) {
    System.out.printf("%-6s %-10.2f %-12s %s%n",
        a.getType(), a.getAmount(), a.getDate(), a.getNote());
}

常见坑

  • ❌ 用 println 拼、不对齐,数字长短不一很难看。
  • ❌ 忘记 .2f 导致金额出现一长串小数(如 35.500000)。

动手练习:把查看方法改成用 printf 输出对齐表格,金额统一两位小数、右对齐。

一句话记住:printf 管对齐;%-宽s 字符串、%-宽.2f 金额;%n 换行。


L7 · 异常处理 —— 输错了也不崩

本节能做什么:用户输入非数字或负金额时,程序温和提示重输,而不是直接甩红字崩溃。

知识点

  • 异常(exception):程序运行时的"意外状况",如把 "abc" 当数字读。
  • try-catch:把"可能出错的代码"放 try,出错后怎么处理写 catch。
  • NumberFormatException:数字格式不对(文字转数字失败)时抛出。
  • 防御式编程:假设用户会犯错,提前堵好路(校验负值、捕获异常)。

代码片段(L7_Exception.java 核心)

System.out.print("金额:");
try {
    double amount = Double.parseDouble(sc.nextLine());
    if (amount <= 0) { System.out.println("金额必须大于 0"); return; }
    accounts.add(new Account("支出", amount, "午饭"));
} catch (NumberFormatException e) {   // 输入的不是数字
    System.out.println("金额必须是数字,录入失败。");
}

常见坑

  • ❌ 不处理异常,用户手滑输字母,整个程序崩掉。
  • ❌ catch 里空着什么都不做,出错后无声无息,更难排查。

动手练习:给金额录入加 try-catch:输非数字或负数时提示重输,而不是直接崩溃。

一句话记住:try 包可能出错的代码,catch 接住异常;把用户输入当"会犯错"来处理。


L8 · 文件持久化 —— 关掉再开还在

本节能做什么:退出前把账目写入文件,启动时读回,数据"活过重启"。

知识点

  • File:代表磁盘上的文件本身。
  • 写:BufferedWriter / FileWriter,逐行把一笔账写成逗号分隔的文本。
  • 读:BufferedReader / FileReader,逐行读回、用 split(",") 拆开还原成对象。
  • try-with-resources:try (...) { } 写法,用完后自动关闭流,避免数据没真正写进去或资源被占。
  • 持久化:把内存里的数据落到磁盘,重启不丢。

代码片段(L8_Persistence.java 核心:保存与读取;完整终态见 AccountBook.java)

// 保存:try-with-resources 自动关流
private void save() {
    try (BufferedWriter bw = new BufferedWriter(new FileWriter("accountbook.txt"))) {
        for (Account a : accounts) {
            bw.write(String.join(",", a.getType(), String.valueOf(a.getAmount()), a.getNote()));
            bw.newLine();
        }
    } catch (IOException e) { System.out.println("保存失败:" + e.getMessage()); }
}
// 读取
private void load() {
    File f = new File("accountbook.txt");
    if (!f.exists()) return;
    try (BufferedReader br = new BufferedReader(new FileReader("accountbook.txt"))) {
        String line;
        while ((line = br.readLine()) != null) {
            String[] p = line.split(",", -1);
            accounts.add(new Account(p[0], Double.parseDouble(p[1]), p[2]));
        }
    } catch (IOException e) { System.out.println("读取失败:" + e.getMessage()); }
}

常见坑

  • ❌ 用完流不关闭,可能数据没写入或占着系统资源——用 try-with-resources 最省心。
  • ❌ 读取时 split 长度不够导致数组越界——先判断 p.length。

动手练习:给之前的程序加存盘:退出时把集合按行写入文件,启动时读回。跑通后你就拥有一个真正能日常用的小工具。

一句话记住:数据落盘才不丢;写用 Writer、读用 Reader;try-with-resources 自动关。

参考:L8_Persistence.java 是只加了持久化的单步版本;AccountBook.java 是完整终态(额外含 id、分类、3.统计)。


L9 · 综合复盘 + AI 协作 —— 你会用 AI 写代码了

本节能做什么:回看 L1→L8 这个记账本怎么一节节长大,并学会用 AI 给它加功能、还能读懂 AI 的代码。

回顾这一路(同一案例螺旋长大)

  • L1 只有一个变量 → L2 有了类 → L3 装进集合 → L4 能交互 → L5 拆成方法 → L6 变整齐 → L7 不崩 → L8 能存盘。

核心认知:AI 是放大器,不是替代品

  • 不懂基础时,你只能含糊地说"帮我加个统计",AI 给的代码你看不懂、改不动;
  • 懂了集合、类、方法后,你能下精准指令:"用 ArrayList 里每笔账的日期,按月份分组算每月总支出"——AI 生成的代码你也能读、能改、能验证。
  • 基础越牢,给 AI 的指令越准,放大效果越强。

参考实现:L9_AI_Extension.java 给出了「按月统计 / 导出 CSV」的参考代码——这就是你给 AI 下精准指令后,可能得到的产出的样子。

动手练习:给 AI 提一个精准扩展需求,比如"导出 CSV"或"按月统计",把它的代码跑通,并试着读懂每行在干什么。

一句话记住:AI 放大你的能力;基础越牢,指令越准,放大越强。


附录 A · 配套 demo 文件清单

文件对应节说明
demo/steps/L1_Variables.javaL1只有变量,存一笔账并打印
demo/steps/L2_AccountClass.javaL2加 Account 类,new 出对象
demo/steps/L3_Collection.javaL3加 ArrayList,存多笔+遍历
demo/steps/L4_Menu.javaL4加 while+if/Scanner 交互菜单
demo/steps/L5_Methods.javaL5把录入/查看拆成方法
demo/steps/L6_Format.javaL6加 printf 对齐表格
demo/steps/L7_Exception.javaL7加 try-catch 防崩
demo/steps/L8_Persistence.javaL8加文件持久化(单步增量,菜单 4 保存 / 5 退出)
demo/steps/L9_AI_Extension.javaL9AI 扩展参考:按月统计 / 导出 CSV
demo/AccountBook.java终态完整成品:在 L8 之上加 id / 分类 / 3.统计(即 L0 成品)

教学时按 L1→L8 顺序放代码,学生能亲眼看到"同一个记账本一点点长大"。

附录 B · 常见错误速查

现象原因解决
金额变整数(35.5→35)用 int 存钱改用 double
比较字符串用 == 永远不对字符串要比内容用 .equals()
输字母程序崩没捕获数字转换异常L7 的 try-catch
菜单退出后还跑/串分支漏写 break补 break / 用 return
文件写了重启没数据流没关闭用 try-with-resources
println 数字对不齐没用格式化L6 的 printf

附录 C · 下一步去哪(P2–P5 预告)

  • P2 数据库:把 ArrayList 换成 MySQL,Account 变成数据库里的表,账不再只存在本地文件。
  • P3 Spring Boot 后端:把菜单逻辑搬进 Controller/Service,提供 REST API。
  • P4 前端 Vue:把控制台界面换成网页,AJAX 调后端。
  • P5 安全与部署:登录鉴权(JWT)、事务、Docker 打包、Linux 上线。
  • 同一记账本,会从"控制台小工具"一路长成"完整全栈应用"。

怎么领:wx:Trdfyl,qq:2356245930,备注「资料」,我把完整版和源码发你,并拉你进答疑群。

本文为 探微编程原创,转载请注明出处

// contact

有需求?先聊聊你的项目

不管是一次技术支持、一个完整项目,还是想补一段工程能力,都可以先沟通。我们会先了解需求并给出判断,再谈方案与报价。

wechat
Trdfyl
qq
2356245930
探微编程 微信二维码

扫码添加微信