Java入门:从HelloWorld到可运行程序的完整实践指南
简介:本资源是《Java基础案例教程(第2版)》配套课后习题答案详解文档,面向Java编程初学者、高校计算机专业学生及自学入门者,旨在帮助读者系统巩固Java核心概念与语法实践。文档覆盖第1章至第3章全部习题,包含填空、判断、选择、简答与编程五大题型,内容紧扣Java起源与特性、开发环境搭建、程序编译运行机制、基础语法(数据类型、运算符、注释)、控制结构(break/continue)、面向对象三大特征(封装/继承/多态)、访问修饰符、变量作用域及类与对象设计等关键知识点,并附有完整可运行的参考代码(如奇数求和、数组最大值查找、Student类封装实现等)。资源为单个50KB的Word(.docx)文件,格式规范、排版清晰,便于打印查阅与对照学习。目前已有6174人下载学习,是夯实Java基础、检验知识掌握程度、提升编程实操能力的实用参考资料。
1. Java 是什么?——别被“编程语言”四个字吓住,它其实像一本会动的菜谱
你有没有试过照着菜谱做一道新菜,结果发现:
- 菜谱里写的“适量盐”,你放了三勺,咸到皱眉;
- “小火慢炖20分钟”,你盯着锅看表,却忘了盖盖子,汤全熬干了;
- 最后端上桌,家人尝了一口说:“这味道……好像和上次不一样?”
Java 就是这样一本「带自动校验功能的智能菜谱」——它不只告诉你“怎么做”,还自带一套「厨房规则检查员」(编译器)和「通用灶台」(JVM,Java虚拟机)。你写下的每行代码,就像切菜、下锅、翻炒的动作,必须符合它的语法逻辑;写完后,它先帮你逐行检查有没有漏盐、错火候(编译),再把这份“标准化操作指令”(字节码)交给任何一台装了JVM的设备(Windows电脑、Mac、Linux服务器,甚至老款安卓手机)去执行。所以你写的程序,在同学的笔记本上能跑,在老师的服务器上也能跑,不是靠运气,而是靠这套“一次编写,到处运行”的底层设计。
它不是给程序员造火箭用的黑科技,而是帮你把想法变成可执行动作的第一块稳当脚手架。学生用它算班级平均分、统计考试最高分;初学者用它写个倒计时闹钟、做个简易学生成绩管理;转行者用它练出第一份能跑通的项目作品集。你不需要懂芯片怎么工作、内存怎么分配,只要愿意从“public class HelloWorld”开始,一行行敲、一次次改、一回回跑通——你就已经在用 Java 说话了。这份《Java基础案例教程(第2版)》课后习题答案,就是那本被无数人翻旧了边、写满批注、贴着便利贴的“实战练习册”,它不讲大道理,只陪你把每个知识点落到能运行的代码上。
2. 为什么新手第一课必须从“HelloWorld”开始:先让电脑听懂你的第一句话
很多零基础同学点开Java教程,看到“JDK”“JVM”“字节码”就头皮发紧,以为得先背完一本词典才能写代码。其实完全相反:Java 学习的第一步,不是理解原理,而是建立“我能让它动起来”的真实手感。就像学骑自行车,没人先让你画传动结构图,而是直接扶你上车、踩踏板、感受平衡。HelloWorld 就是那个“扶你上车”的瞬间。
2.1 这行代码到底在干什么?——拆解成买菜做饭的日常动作
我们来看最原始的 HelloWorld.java:
public class HelloWorld { public static void main(String[] args) { System.out.println("这是第一个 Java 程序!"); } }别急着记语法,咱们用买菜做饭来类比:
| Java 代码部分 | 类比生活场景 | 白话解释 |
|---|---|---|
public class HelloWorld | 给这道菜起个正式名字叫《番茄炒蛋入门版》 | class是 Java 的基本单位,就像“一道菜”;HelloWorld是你给它的名字,必须和文件名(HelloWorld.java)严格一致,就像菜名不能写成《番茄炒蛋V2》但菜谱文件却叫“番茄炒蛋入门版.docx”——系统会找不到。 |
public static void main(String[] args) | 厨房总开关按钮,写着“按这里启动整套流程” | 这是 Java 程序的唯一入口。main方法就像厨房总闸,没有它,再好的菜谱(代码)也通不了电。String[] args是预留的“外卖备注栏”,暂时空着没关系。 |
System.out.println("这是第一个 Java 程序!"); | 把刚炒好的菜盛进盘子,端到餐桌上 | System.out.println()是 Java 的“打印输出”指令,相当于把括号里的文字(字符串)原样显示在屏幕上。“;”是句号,告诉电脑:“这句话说完了,请执行。” |
提示:Java 对大小写极其敏感。
System必须大写 S,out必须小写,println是 p-r-i-n-t-l-n,少一个字母或错大小写,编译就会报错。这不是刁难,而是像菜谱写“加盐5g”不能写成“加言5g”——机器只认精确符号。
2.2 动手跑通它:四步走,不装一堆工具也能起步
你不需要下载几十个G的开发环境,现在就能用最轻量的方式验证:
步骤 1:新建一个纯文本文件
- 在电脑桌面右键 → 新建 → 文本文档
- 把它重命名为
HelloWorld.java(注意:后缀必须是.java,不是.txt!如果看不到后缀,需在文件夹选项中勾选“显示文件扩展名”)
步骤 2:用记事本打开,粘贴上面那段代码
- 复制粘贴时,确保所有符号都是英文半角:括号
()、花括号{}、引号""、分号;——中文输入法下的符号(如“(”、“【”、“””)会导致编译失败。
步骤 3:打开命令行(CMD 或 Terminal),定位到文件所在目录
- 比如文件在桌面,就输入:
cd Desktop - 然后执行编译命令:
javac HelloWorld.java如果提示
'javac' 不是内部或外部命令,说明还没装 JDK。别慌——这是新手最常卡住的第一关,我们下一章专门解决。
步骤 4:编译成功后,运行它
- 命令行里再输入:
java HelloWorld - 屏幕上立刻出现:
这是第一个 Java 程序!
恭喜!你刚刚完成了人生第一个 Java 程序。它没做复杂计算,没连数据库,但它证明了一件事:你写的文字,真的能被电脑读懂、执行、反馈给你。这种“我说,它听,它做,我看见”的闭环,是建立编程信心最关键的一步。
2.3 为什么非得是“HelloWorld”,而不是“计算器”或“学生管理系统”?
因为初学者最大的敌人不是技术难度,而是挫败感积累。
- 写一个计算器,要处理输入、运算符识别、结果展示,中间一步出错(比如把
+写成=),你根本不知道是输入逻辑错了,还是输出格式错了,还是变量没定义。 - 而 HelloWorld 只有三要素:定义类名、定义入口方法、输出一句话。出错只可能在这三处,排查路径极短。
- 它像学钢琴先练“中央C”,像学书法先写“永字八法”——用最小成本,确认整个链条(编辑→保存→编译→运行→输出)是通的。后续所有复杂功能,都是在这个通路基础上,一段段往上搭积木。
3. JDK 是什么?——别把它当成“软件”,它其实是你的 Java 厨房套装
很多新手搜“Java怎么安装”,点开官网看到 JDK 下载页,面对“JDK 21”“JDK 17 LTS”“JDK 8”一堆版本,瞬间懵了:“我该下哪个?LTS 是啥?21 和 8 差在哪?”
其实不用纠结版本号。JDK 就像你租的精装公寓:厨房里已经配好了灶台(JVM)、抽油烟机(垃圾回收器)、刀具架(编译器 javac)、量杯(调试工具 jdb)、甚至还有食谱索引(文档)。你不需要自己砌灶、接排烟管、打刀,拎包入住就能开火。而“JDK 17”“JDK 21”只是不同年份出厂的精装房,基础功能(炒菜、煮面、蒸馒头)完全一样,新版可能多了智能控温(新语法糖)或更省气(性能优化),但对刚学煎蛋的新手,JDK 17 就是最稳妥的选择——它是长期支持版(LTS),意味着未来好几年都有官方维护,教程、书籍、公司项目都优先适配它。
3.1 JDK 里到底装了啥?——一张厨房设备清单
| JDK 组件 | 类比厨房设备 | 作用 | 新手是否必须懂? |
|---|---|---|---|
javac.exe(编译器) | 食材预处理机 | 把你写的.java源代码(人话菜谱)翻译成.class字节码(机器能懂的标准化指令)。就像把“番茄切滚刀块”翻译成“番茄→切→3cm×3cm×3cm立方体”。 | ✅ 必须知道它存在,且要用它编译。但不用懂翻译原理。 |
java.exe(解释器/启动器) | 万能灶台(JVM) | 加载.class文件,把它一行行“做出来”,最终显示结果。关键在于:同一份.class文件,能在 Windows、Mac、Linux 的 JVM 上直接运行,不用重写。 | ✅ 必须知道它是运行程序的命令。 |
javadoc.exe | 电子版《中华菜谱大全》 | 根据代码里的/** */注释,自动生成标准文档。新手现在不用,但以后读别人代码时会感激它。 | ❌ 暂时跳过。 |
jdb.exe | 厨房监控摄像头 | 调试时用,能看到程序运行到哪一步、变量当前值是多少。新手先用System.out.println()打印调试就够了。 | ❌ 后期再学。 |
bin目录 | 厨房工具抽屉 | 所有可执行程序(javac,java,javadoc)都在这里。安装 JDK 后,必须把bin目录路径添加到系统环境变量PATH中,否则命令行里打javac会提示“找不到”。 | ✅ 必须操作,但只需复制粘贴一条路径。 |
注意:网上有些教程让你装“JRE”(Java Runtime Environment),那是只给用户运行 Java 程序用的(只有
java.exe,没有javac.exe)。学编程必须装 JDK,不是 JRE。就像学做菜,你得有菜刀(编译器),不能只等着吃现成的。
3.2 三分钟装好 JDK:避开“环境变量”玄学的实操方案
新手最怕“配置环境变量”,总觉得要改注册表、输一串神秘代码。其实现代 JDK 安装包(如 Oracle JDK 或 OpenJDK)已极大简化:
方案 A:用图形化安装器(推荐给第一次安装者)
- 去官网下载JDK 17 Windows x64 Installer(后缀是
.exe,不是.zip) - 双击运行,一直点“下一步”,唯一要注意的是安装路径:
- 默认可能是
C:\Program Files\Java\jdk-17 - 建议改成
C:\Java\jdk-17(路径不含空格和中文,避免后续报错)
- 默认可能是
- 安装完成,打开命令行(Win+R → 输入
cmd→ 回车),输入:
如果显示类似java -versionjava version "17.0.1",说明安装成功!✅ 这是因为新版安装器默认帮你配好了
PATH,你不用手动操作。
方案 B:如果用了.zip解压版(或安装后java -version报错)
你需要手动把bin目录加到PATH:
- 右键“此电脑” → “属性” → “高级系统设置” → “环境变量”
- 在“系统变量”里找到
Path,点击“编辑” → “新建” → 粘贴你的 JDKbin路径,例如:C:\Java\jdk-17\bin - 点“确定”保存,关闭所有已打开的命令行窗口,重新打开一个新的,再试
java -version。
3.3 常见问题排查:为什么我的javac总是“找不到”?
这是新手血泪高频翻车区,别怀疑自己,90% 是路径或空格惹的祸:
| 现象 | 原因 | 解决 |
|---|---|---|
javac不是内部命令,但java -version能显示版本 | JDK 安装了,但javac.exe所在的bin目录没加到PATH,或者加错了位置(比如加到了“用户变量”而非“系统变量”) | 重新检查环境变量Path,确认C:\Java\jdk-17\bin这一行存在且拼写正确,重启命令行。 |
javac HelloWorld.java报错:错误: 类 HelloWorld 是公共的, 需要在名为 HelloWorld.java 的文件中声明 | 文件名和public class名不一致。比如文件叫hello.java,但代码里写public class HelloWorld | 严格保证:文件名 =public class后的名字 +.java。删掉旧文件,新建HelloWorld.java,粘贴代码。 |
编译通过(无报错),但java HelloWorld报错:错误: 找不到或无法加载主类 HelloWorld | 你在错误的目录下运行了java命令。java命令必须在.class文件所在目录执行,且类名不能带.class后缀 | 用dir(Windows)或ls(Mac/Linux)确认当前目录下有HelloWorld.class文件;运行命令是java HelloWorld,不是java HelloWorld.class。 |
| 中文乱码(如显示“杩欐槸绗竴涓?Java 绫荤▼搴?!”) | 源文件保存编码不是 UTF-8,或命令行默认编码不匹配 | 用记事本另存为时,选择“UTF-8”编码;或在命令行输入chcp 65001(切换为 UTF-8 模式)后再运行。 |
提示:从那以后我每次新建 Java 文件,都强制用 VS Code 或 Notepad++ 打开,右下角确认编码是 UTF-8,保存前再看一眼文件名和类名是否咬死——这个习惯帮我避开了至少一半的入门期编译报错。
4. 从填空题到能跑的代码:如何把课后答案变成你的实战脚手架
拿到这份《Java基础案例教程(第2版)》课后习题答案,别急着从头抄到尾。它不是一本“答案书”,而是一套分阶段解锁的通关地图。每一章的答案,对应一个明确的能力关卡:第1章考你环境是否搭好,第2章考你语法是否写对,第3章考你能不能把现实问题(如学生成绩)抽象成对象,第4章考你能否用继承和多态让代码更灵活…… 把它当“参考答案”用,容易陷入“抄完就忘”;把它当“调试对照表”用,才能真正长本事。
4.1 第2章编程题:计算1~99奇数和——为什么for循环里要写i < 100?
先看原题答案:
public class getSum { public static void main(String[] args) { int sum = 0; for (int i = 1; i < 100; i++) { if (i % 2 != 0) sum += i; } System.out.println(sum); } }新手常问:“i < 100是不是应该写i <= 99?i % 2 != 0是不是可以写成i % 2 == 1?”
这恰恰是动手的好时机——不要只信答案,要亲手改、亲手试、亲手看结果。
尝试1:把i < 100改成i <= 99
- 结果:完全一样,输出
2500。 - 原因:
i < 100表示i从 1 到 99(不包括100),i <= 99也是从 1 到 99。两者等价。Java 中习惯用i < 上限,因为数组索引、循环边界普遍采用“左闭右开”区间(如arr[0]到arr[arr.length-1]),统一思维更不易错。
尝试2:把i % 2 != 0改成i % 2 == 1
- 结果:还是
2500。 - 原因:
i % 2的结果只能是0(偶数)或1(奇数),所以!= 0和== 1逻辑等价。但注意:如果i是负数(如-3 % 2在 Java 中等于-1),== 1就会失效,而!= 0依然正确。虽然本题i从1开始不会负,但养成用!= 0判断奇偶的习惯,能避免未来踩坑。
尝试3:删掉if判断,直接sum += i
- 结果:输出
4950(1+2+...+99 的和)。 - 原因:
for循环本身是遍历所有数,if是筛选条件。去掉它,就变成了求全部数的和,不再是“奇数和”。
这就是课后答案的价值:它不是终点,而是你动手实验的起点。每一次微小的修改,都是在和 Java 对话,听它用报错或结果告诉你“这里怎么想才对”。
4.2 第3章 Student 类:封装不是“加 private 就完事”,而是划清责任边界
Student 类的代码很长,新手容易被一堆getXXX()setXXX()方法绕晕。其实核心就一条:封装 = 把数据(属性)和操作数据的方法(行为)打包在一起,并控制外部访问权限。
看关键片段:
public class Student { private String sNo; // 学号 → 外部不能直接读写 private String sName; // 姓名 → 外部不能直接读写 // ... 其他 private 属性 // 提供公共方法,让外部安全地读取 public String getsName() { return sName; } // 提供公共方法,让外部安全地修改(可加校验) public void setsName(String sName) { if (sName != null && !sName.trim().isEmpty()) { this.sName = sName; } else { System.out.println("姓名不能为空!"); } } }类比:银行保险柜
private String sName就像保险柜里的现金,只有柜员(类内部)能直接碰。getsName()是柜员提供的“余额查询单”,你只能看,不能改。setsName()是柜员提供的“存款/取款窗口”,你递进去钱(参数),柜员(方法体)先检查真假(if校验),再决定是否存入。- 如果你不走窗口,非要撬锁(直接
student.sName = "张三"),对不起,编译器直接拦住:“sName是私有的,你没权限!”——这就是封装的保护力。
4.3 第4章员工工资系统:继承不是“抄代码”,而是“定义谁管什么”
SalariedEmployee(月薪员工)、HourlyEmployee(时薪员工)、SalesEmployee(销售员工)都继承自 Employee(员工基类)。新手容易误解:“继承=把父类代码复制一遍”。错!继承是“能力继承”,不是“代码复制”。
看关键设计:
// Employee 是所有员工的共同模板:都有姓名、生日月份、生日奖金 abstract class Employee { private String name; private int month; // ... 构造、getter/setter public double getSalary(int month) { // 生日当月多发100元 return this.month == month ? 100 : 0; } } // SalariedEmployee 只需专注“月薪怎么算”,生日奖金逻辑复用父类 class SalariedEmployee extends Employee { private double monthSalary; public double getSalary(int month) { return monthSalary + super.getSalary(month); // super. 调用父类逻辑 } }类比:连锁奶茶店总部与分店
- 总部(Employee)定下铁律:“所有分店生日月必须送顾客一杯免费奶茶(100元)”。
- 北京分店(SalariedEmployee)说:“我每月固定营收5万,加上总部送的奶茶,总营收就是5万+100”。
- 上海分店(HourlyEmployee)说:“我按小时算钱,本月工时×单价,再加总部送的奶茶”。
- 总部不用管每家店具体怎么赚钱,只管“送奶茶”这一条底线。分店也不用重复写“送奶茶”逻辑,直接
super.getSalary()就调用总部规则。 - 这就是继承的威力:父类管“不变的部分”(生日奖金),子类管“变的部分”(薪资计算方式),代码清晰,修改方便(比如总部改规则,所有分店自动生效)。
5. 避坑指南:新手必踩的5个“看似简单实则致命”的坑
刚入门时,你以为的“小问题”,往往是阻断学习流的最大石头。这些坑,我当年在模拟项目X里反复摔过,也看过A同学在实验室调试到凌晨三点就为一个分号。列在这里,不是吓你,是帮你绕开它们,把时间花在真正值得的地方。
5.1 坑1:中文标点混入代码——最隐蔽的“编译失败”
- 现象:代码看起来和答案一模一样,但
javac一运行就报error: 非法字符: '\u3000'或error: 需要 ';'。 - 原因:你用中文输入法写了括号
()、引号“”、分号;、甚至空格(中文全角空格\u3000)。Java 只认英文半角符号。 - 解决:
- 写代码前,务必切到英文输入法(Ctrl+空格 或 Shift);
- 在编辑器(如 VS Code)里开启“显示不可见字符”(通常在设置里搜
renderWhitespace),中文空格会显示为·,一眼揪出; - 粘贴代码时,先粘贴到记事本,再从记事本复制到编辑器——记事本会自动过滤掉大部分格式。
5.2 坑2:文件名与类名不一致——“找不到主类”的元凶
- 现象:
javac HelloWorld.java成功,但java HelloWorld报错误: 找不到或无法加载主类 HelloWorld。 - 原因:文件名是
helloworld.java(小写),但类名是public class HelloWorld(大写H)。Java 规定:public类的名称必须与文件名完全一致(包括大小写)。 - 解决:
- 删除旧文件;
- 新建文件,严格按类名命名:
HelloWorld.java; - 确认文件后缀是
.java,不是.java.txt(Windows 默认隐藏后缀,需在文件夹选项中勾选“显示文件扩展名”)。
5.3 坑3:main方法签名写错——“程序不运行”的静默杀手
- 现象:编译通过,运行无报错,但屏幕一片空白,什么也不输出。
- 原因:
main方法签名写成了public static void main(String args)(少了[]),或public static void main(string[] args)(string小写)。Java 要求必须是String[] args(String大写,[]在类型后)。 - 解决:
- 记住口诀:“
public static void main,String大写带方括号,args是变量名,可改但别丢”; - 复制粘贴时,整行复制,不要手敲,避免大小写或符号遗漏。
- 记住口诀:“
5.4 坑4:数组越界——“ArrayIndexOutOfBoundsException”的日常
- 现象:程序运行到某行突然崩溃,报
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5。 - 原因:数组长度是5,索引范围是
0到4,但你写了arr[5](试图访问第6个元素)。常见于for循环条件写成i <= arr.length(应为i < arr.length)。 - 解决:
- 记住:数组索引从0开始,最大索引 =
length - 1; - 循环条件永远用
i < arr.length,不是i <= arr.length; - 调试时,在访问数组前加一句
System.out.println("arr.length=" + arr.length + ", i=" + i);,实时看数值。
- 记住:数组索引从0开始,最大索引 =
5.5 坑5:==误用于字符串比较——“明明相等却不相等”
- 现象:
String a = "hello"; String b = "hello"; if (a == b) { ... }有时成立,有时不成立,逻辑混乱。 - 原因:
==比较的是内存地址(两个变量是否指向同一个对象),而equals()比较的是内容是否相同。字符串常量池机制导致某些"hello"可能共用地址,但这是特例,不可依赖。 - 解决:
- 所有字符串内容比较,无条件用
equals():if (a.equals(b)); ==只用于基本数据类型(int,char,boolean)或判断对象是否为null(if (str != null))。
- 所有字符串内容比较,无条件用
从那以后我每次写
==,都强制停顿半秒,问自己:“这是基本类型吗?还是在判空?如果不是,立刻改成.equals()。” 这个肌肉记忆,让我再也没为字符串比较掉过头发。
6. 下一步学什么?——从“能跑通”到“能设计”的三阶跃迁路径
你现在能编译 HelloWorld,能算奇数和,能创建 Student 对象,甚至能看懂员工工资系统的继承关系——这已经远超大多数“只看不练”的初学者。但真正的编程能力,不在于你会多少语法,而在于遇到一个新问题,能否拆解、建模、落地。接下来,别急着冲向 Spring Boot 或大数据,先稳扎稳打,沿着这条三阶路径走:
6.1 第一阶:把“写代码”变成“解问题”——用 Java 实现一个真实小需求
目标:不再抄答案,而是独立完成一个完整的小项目。
推荐项目:学生成绩分析工具
- 输入:从文本文件读取5名学生的姓名、Java成绩(如
Tom,85); - 处理:计算平均分、最高分、最低分;
- 输出:将结果写入新文件,并在控制台打印。
- 涉及技能:
FileReader/BufferedReader(第7章 IO)读文件;String.split(",")拆分姓名和成绩;ArrayList<Student>存储学生列表(第6章集合);Collections.sort()排序(可选,加深理解);FileWriter写结果。
为什么选它?因为需求清晰(老师布置作业、家长查成绩)、数据简单(文本行)、反馈直接(文件生成成功即成功)。你不必追求界面美观,只要
java ScoreAnalyzer运行后,result.txt里有平均分:82.4,你就完成了从“语法练习”到“问题解决”的质变。
6.2 第二阶:让代码“活”起来——加入异常处理与日志
当前你的代码很“脆”:文件不存在就崩溃,成绩输成字母就报错。真实世界不允许这样。
关键补丁:
- 用
try-catch包裹文件读写(FileNotFoundException,IOException); - 用
Integer.parseInt()转成绩时,捕获NumberFormatException,提示“成绩格式错误,请输入数字”; - 用
System.out.println()打印关键步骤(如“正在读取文件...”“共读取5条记录”),形成简易日志。
这不是炫技,而是培养“防御性编程”思维:假设所有外部输入都不可信,所有资源都可能失败,你的代码必须优雅地应对。这是专业程序员和爱好者最本质的分水岭。
6.3 第三阶:从“单机程序”走向“可交互”——用 Scanner 接收用户输入
告别硬编码!让程序真正和人对话。
改造你的成绩分析工具:
- 启动时,用
Scanner问:“请输入学生人数:”; - 循环中,问:“请输入第1位学生姓名:”,“请输入第1位学生Java成绩:”;
- 输入完成后,再执行计算和输出。
- 涉及技能:
Scanner.nextLine()(读字符串)、Scanner.nextInt()(读整数)、注意nextInt()后的换行符残留问题(用nextLine()吃掉)。
这一步的意义,是打破“程序=固定流程”的幻觉。用户输入是动态的、不可预测的,你的代码必须能适应变化。当你第一次看到程序等待你敲回车、然后精准输出结果时,那种掌控感,会彻底点燃你继续深入的热情。
最后送你一句我带A同学时的口头禅:“别怕写错,怕的是不敢删掉重写。”
你手里的这份课后答案,不是标准答案,而是你第一次写错时,可以回头对照的“镜子”;是你卡壳时,能快速验证思路的“快照”;更是你从“跟着做”走向“自己想”的那根拐杖。
希望帮到你。
本文还有配套的精品资源,点击获取