简介:深圳大学《Java程序设计》实验报告与源代码合集,完整收录课程多个必做与选做实验,内容扎实、结构清晰,面向正在学习Java基础或进阶知识的在校生、自学者及备考者。资源以实验为主线,覆盖面向对象编程、集合框架与线程同步、Swing界面开发、I/O与对象序列化、Socket网络通信、JDBC数据库操作以及常用设计模式等知识点;既有基础语法、异常处理和文件操作等必实验,也有GUI、网络、数据库和设计模式等进阶选实验,适合按课程进度对照练习,也可用于期末复习和课程设计参考。压缩包共118个文件,以76份Java源代码和15份docx实验报告为主体,另含PDF、Markdown笔记、压缩包及若干配置文件,总大小约49.57MB;目录按实验编号组织,源码、报告与说明文档相互关联,实验报告还包含设计思路、关键代码解释和运行结果,便于按需查找与本地运行。已有861人学习浏览,适合想要通过完整实验案例、可运行代码及配套文档来巩固Java开发能力的读者。
1. 某高校 Java 程序设计实验包:报告和源码能不能直接落地
Java 课程作业最折磨人的不是语法,而是代码在你自己电脑上跑得欢,换成老师的机器就各种报错。这套来自某高校《Java程序设计》课程的实验报告和源代码,把环境搭建、变量与控制流、面向对象、集合与文件 IO、GUI、多线程的完整实验链一起打包,每个实验都配对应 .java 源码和按学校模板写的实验报告,报告里流程图、运行截图、结果表格的位置都预留好了。适合三类人:实验报告拖到截止前的人、想参考一套完整报告结构的人、以及想把手头的课程作业写成规范工程的新手。下面按工程组织、源码拆解、报告填法和踩坑顺序,把整套资源实际拆一遍。
2. 实验源码的工程组织:目录结构、JDK 版本与本机复跑步骤
拿到压缩包先别急着双击运行,我一般先看目录,再确认 JDK 版本,最后才编译。这一步能帮你避开一半的“代码没问题环境有问题”。
2.1 一份标准实验项目该有的目录结构:别把编译产物混进源码
这套资源的目录组织方式非常典型,几乎就是教学环境里标准 Java 项目的骨架:
java-course-lab/ ├── src/ # 所有 Java 源码,按实验分包 │ ├── lab01_hello/ # 实验一:JDK安装与第一个程序 │ ├── lab02_control/ # 实验二:运算符与流程控制 │ ├── lab03_oop/ # 实验三:类与对象、继承、接口 │ ├── lab04_collection/ # 实验四:集合框架与泛型 │ ├── lab05_fileio/ # 实验五:文件字符流与字节流 │ └── lab06_thread/ # 实验六:多线程与线程同步 ├── out/ # 编译后的 class 输出,提交前删掉 ├── docs/ # 实验报告 docx 和运行截图 │ ├── 实验一报告.docx │ └── 运行截图/ └── README.md # 每个实验的编译运行命令src 目录按 lab01 到 lab06 分包,每个包里通常是一个 Main 启动类和两三个辅助类。这种组织方式最大的好处是源码和实验报告里的“实验步骤”章节一一对应,你写报告时不必再回忆某个类在哪个实验里出现过。out 目录是编译产物,交作业时一定要删掉。我看到不少同学把整个项目文件夹直接压缩,连带着 IDE 的配置目录、class 文件一起提交,老师在 Eclipse 里一打开就是一堆红色报错,第一印象就很差。
README.md 如果写了编译命令,这份报告基本不会出现“不知道怎么运行”的评语。这套资源里每个实验都带一个 README 片段,内容是 javac 编译命令、java 运行命令、参数示例。你拿到后第一步应该做的,是把所有 src 下面的 java 文件按实验编号跑一遍。另外,我建议全局搜索一遍源码里的绝对路径,比如 C:\Users\xxx\Desktop 这种盘符路径,换机器必挂。搜索到就直接替换成相对路径,否则你在自己机器上能跑,到老师机器上一律 FileNotFoundException。
2.2 控制台还是 GUI:根据实验评分点选实现方案,别跟风加花活
很多同学看到实验六要求多线程,就硬上 Swing 写个进度条界面,结果线程同步没处理好,窗口卡死,报告截图里全是“无响应”对话框。前三个实验用控制台程序是完全合理的,因为评分点写得清楚:正确性占大头,界面再花哨也救不回来。后面实验如果题目明确说“图形界面”,再考虑 GUI 方案。
GUI 选 Swing 还是 JavaFX,取决于你安装的 JDK 版本。JDK 8 自带的 Swing 在后续版本里也能用,JavaFX 在 JDK 11 以后需要单独引入模块,如果任课老师的编译环境没有配 JavaFX,你交一个 JavaFX 项目大概率跑不起来。稳妥做法是:题目没说界面库,就用 Swing;说了界面,先确认老师机器上有没有 JavaFX 运行时。这套资源里的 GUI 相关实验用的是 Swing,避免额外依赖,这一点在实际复用中很省事。
如果你不想在 GUI 上耗时间,可以用纯控制台完成多线程实验,把输出结果贴进报告。多数题目只要求“模拟”,不强制界面。把时间花在锁和同步上比做界面划算,等你自己改造简历项目时再补界面也不迟。
2.3 本机复跑的三条命令:编码、包名和参数都要对齐
从命令行手动编译运行,比 IDE 一键运行更能暴露环境问题。我一般推荐三步走:
# 进入实验四源码目录 cd src/lab04_collection # 编译所有 java 文件,显式指定 UTF-8 编码 javac -encoding UTF-8 *.java -d ../../out # 带包名运行主类,传入随机种子参数 42 java -cp ../../out lab04_collection.Main 42javac 后面加-encoding UTF-8,是为了避免 Windows 默认 GBK 和源码文件 UTF-8 不一致导致的中文乱码,这是课程作业里最高频的翻车点。运行命令用-cp指定 classpath,告诉 JVM 去 out 目录找编译产物。最后一个参数 42 是传给 Main 的随机种子,在实验四的随机点名场景里,固定种子能让结果可复现——这一条在报告里是加分项,后面第 3 章会细说。
按包名运行经常会遇到一个低级错误:在主类所在的目录里直接运行 java Main,而不是回到 src 上一级用全限定名。错误提示是“找不到或无法加载主类 Main”。正确做法是java -cp out lab04_collection.Main,类名必须带包路径。这套资源里的每个 Main 类都带包名,如果你要改包名,记得同步改目录结构、文件第一行的 package 声明和运行命令三处,只改一个地方,编译和运行至少挂一个。
如果你习惯用 IDE,也要确认两处:项目编码设为 UTF-8,JDK 版本和老师一致(大多数教学环境是 JDK 8 或 11)。这两处不一致,代码可能在你电脑上正常、在老师电脑上报错,最典型的是用了 var 关键字或新版 switch 表达式,老旧 JDK 直接拒编。还有一点,报告里的运行截图不要拿 IDE 的编辑区截图,要拿终端输出截图,编辑区截图只能证明你写了代码,不能证明代码跑通了。
3. 四个高频实验模块的源码拆解:集合、文件 IO、多线程与 Swing 的关键写法
这一章选资源里可复用度最高的四个模块,直接看代码。每一段代码我都标注了参数作用和容易写错的地方,你可以对照自己的题目改参数量。
3.1 随机点名与集合去重:固定随机种子,报告结果才能复现
实验四一般会出随机点名或者扑克牌洗牌题,核心代码是:
import java.util.*; public class RandomPicker { public static void main(String[] args) { List<String> names = new ArrayList<>(); Collections.addAll(names, "A同学", "B同学", "C同学"); // 种子参数从命令行传入,固定种子后每次运行结果一致 long seed = Long.parseLong(args[0]); Collections.shuffle(names, new Random(seed)); System.out.println("被点名的是:" + names.get(0)); } }逻辑说明:shuffle方法的第二个参数必须传入 Random 对象,如果你直接调用Collections.shuffle(names),每次运行顺序都不同,报告截图里的结果和老师复跑的结果对不上,这是最容易被质疑的一点。固定随机种子之后,你作业截图里出现的结果和老师复跑的命令行结果完全一致,天然支持报告里“实验可重复性”的小结。参数说明:args[0]是随机种子,建议选一个小整数比如 42;运行时不带参数会抛出ArrayIndexOutOfBoundsException,所以入口方法里最好加一个长度判断,或者给默认值。
3.2 成绩单文件读写:编码和换行符决定文件能否被老师打开
文件 IO 实验通常是读一个文本成绩单、按规则处理、写到新文件:
import java.io.*; import java.nio.charset.StandardCharsets; import java.util.*; public class ScoreProcessor { public static void main(String[] args) throws IOException { String inputPath = args.length > 0 ? args[0] : "scores.txt"; List<String> lines = new ArrayList<>(); // 显式指定 UTF-8 读取,避免 Windows 下默认编码不一致 try (BufferedReader reader = new BufferedReader( new InputStreamReader(new FileInputStream(inputPath), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { lines.add(line.trim()); } } // 模拟处理:把空行过滤后按行写入新文件 try (BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream("scores_out.txt"), StandardCharsets.UTF_8))) { for (String l : lines) { if (!l.isEmpty()) { writer.write(l.replaceAll("\\s+", ",")); writer.newLine(); } } } System.out.println("处理完成:" + lines.size() + " 行有效数据"); } }逻辑说明:InputStreamReader套上StandardCharsets.UTF_8,是解决乱码的标准做法。如果你不传编码,JVM 会用操作系统的默认字符集,Windows 下是 GBK,代码在 Linux 老师机上运行读出来就是乱码。BufferedWriter的newLine()方法会根据操作系统自动换行;如果你图省事写\n,再到 Windows 记事本打开,换行就全乱了。参数说明:程序支持把输入文件名作为args[0]传入,不传就默认读同目录下的 scores.txt。这一层参数化让实验报告里可以写“本程序支持指定外部文件”,评分老师很吃这一条。
3.3 多线程模拟售票:synchronized 锁的位置决定数据是否出错
多线程实验经典题是售票窗口,代码通常写成这样:
public class TicketTask implements Runnable { private static int tickets = 10; @Override public void run() { while (true) { // 把判断和操作放进同一把锁里,保证原子性 synchronized (TicketTask.class) { if (tickets <= 0) { System.out.println(Thread.currentThread().getName() + " 发现票已售罄"); break; } System.out.println(Thread.currentThread().getName() + " 卖出第 " + tickets + " 张"); tickets--; try { Thread.sleep(50); // 模拟出票耗时 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } public static void main(String[] args) throws Exception { Thread t1 = new Thread(new TicketTask(), "窗口1"); Thread t2 = new Thread(new TicketTask(), "窗口2"); t1.start(); t2.start(); } }逻辑说明:synchronized(TicketTask.class)锁的是类对象,保证多个窗口线程互斥进入临界区。“先判断余票、再出票、再减少余票”三件事必须在同一把锁内完成。如果只锁tickets--那一句,判断和减少之间其他线程会插进来,最后卖出的票数大于总量。运行多次你会发现票数正确与否完全由锁的位置决定,这是多线程实验的核心考点,也是答辩时老师最爱问的点。参数说明:Thread.sleep(50)是模拟耗时,单位毫秒,你可以改成 100 或 200 观察线程调度差异,报告里就能写“通过调整休眠时间观察线程交替输出顺序的变化”。
3.4 Swing 界面初始化:线程、事件和 EDT 的关系
实验五或六如果有界面要求,主类大致长这样:
import javax.swing.*; public class SimpleCounter extends JFrame { private JLabel countLabel = new JLabel("0"); private int count = 0; public SimpleCounter() { setTitle("计数器Demo"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(300, 200); setLayout(new java.awt.FlowLayout()); add(new JButton(new AbstractAction("加一") { @Override public void actionPerformed(ActionEvent e) { count++; countLabel.setText(String.valueOf(count)); } })); add(countLabel); setVisible(true); } public static void main(String[] args) { // Swing 界面必须在事件分发线程中创建 SwingUtilities.invokeLater(SimpleCounter::new); } }逻辑说明:所有 Swing 组件创建和更新必须在 EDT 事件分发线程上执行,直接在主线程里 new JFrame 虽然大多数时候能显示,但触发快速连续点击时界面会闪烁或卡顿。这行SwingUtilities.invokeLater是标准写法。加一按钮的事件通过AbstractAction匿名内部类实现,它运行在事件线程里,更新 countLabel 是线程安全的——这一点在报告“线程模型”小节可以直接引用。参数说明:setSize与布局管理器共同决定窗口排布;忘写setVisible(true)是新手最常见的界面不显示原因,代码跑起来没窗口,第一反应应该是检查它。
补充一个极其常见的编译错误:在actionPerformed里访问外部局部变量,Java 要求局部内部类只能访问 effectively final 的局部变量。如果你在事件回调里给 count 重新赋值,编译期就会告诉你variable used in inner class should be final or effectively final。解决办法是把这个变量改成成员变量,代码里 count 是类的字段,就不受这个限制。拿到源码后,不要整包复制到自己的作业里,把每个实验的核心算法和关键写法抽出来,对照自己的题目改参数量,才能真正理解为什么锁要放在那里、为什么编码要显式指定。
4. 实验报告撰写模板:把代码截图、流程图和结果表格填进对的位置
代码能跑只是第一步,实验报告通常占三到四成分数。很多重交不是因为代码有问题,而是报告里截图无效、流程缺失、结果表格对不上代码。
4.1 报告结构与字数分配:五段式按评分点写
多数学校的实验报告要求五段:实验目的、实验环境、实验原理与流程、运行结果与截图、总结。这套资源里的报告就是按这个结构写的,模板段落可以直接复用。
| 报告段落 | 具体内容 | 参考篇幅 | 评分老师看什么 |
|---|---|---|---|
| 实验目的 | 2~3 条,写“掌握 XX 类的使用” | 60~100 字 | 是否真的做了 |
| 实验环境 | JDK 版本、操作系统、IDE 名称 | 40~60 字 | 环境是否一致 |
| 实验原理与流程 | 核心类关系、流程图、关键代码 | 300~500 字 | 流程是否完整 |
| 运行结果 | 截图、输入输出表格 | 300~500 字 | 结果与截图是否一致 |
| 总结 | 遇到的问题和解决方法 | 150~250 字 | 是否有独立思考 |
“实验目的”别写空话,像“本次实验让我加深了对 Java 的理解”这种话等于没写。要写具体的:掌握了 ArrayList 与 LinkedList 的适用场景、掌握了 BufferedReader 的按行读取、理解了 synchronized 的互斥范围。“实验环境”一定要写 JDK 版本,比如 JDK 8u202,因为代码在新版 JDK 上编译通过、在旧版上报语法错误时,这一行能帮你说明环境差异。
“实验原理与流程”是整份报告的大头。你要画一张流程图画清楚程序从启动到输出的路径,代码片段只贴核心部分,不要整个 Main 类粘进去。比如随机点名实验,流程图走:读取名单 → 输入种子 → shuffle → 输出第一个人名。再配 5 到 10 行关键代码就够了,剩下的空间留给运行结果。
“总结”写你实际踩过的坑。同样一个实验,写“遇到了中文乱码,通过指定 UTF-8 编码解决”比写“本次实验非常顺利”得分高得多。老师能分辨哪些是复制的模板话,哪些是真做过。
4.2 截图与流程图:带命令行上下文的截图才算有效证据
截图这块有硬规矩:不要截 IDE 编辑区,要截终端或者运行窗口。一份有效截图必须让人能从图里看到完整命令和完整输出,我一般这样做:
第一步:打开命令行,执行编译命令 第二步:执行运行命令,把带输入参数的一行和输出结果一起截进去 第三步:如果程序有交互输入,把输入的内容和对应的输出截在同一张图里很多同学截的图是代码编辑区加一个绿色小三角,这只能证明你点了运行按钮,不能证明程序是通过命令行编译运行的。老师复查的时候第一条就是自己在命令行跑一遍,你的截图如果连命令都没有,说服力直接减半。
流程图用 draw.io 或者 ProcessOn 画,不要用 Word 自带的形状硬拼。画完导出成 PNG 插入报告,分辨率设高一点,别用截图工具截网页上的图,那种图放大就糊。流程图里的判断框文字要和代码里的条件一致,比如“余票是否大于 0”对应代码里的if (tickets <= 0),图与代码不一致是报告里相当扎眼的硬伤。
4.3 运行结果对照表:输入、预期输出、实际输出三列写满
运行结果部分,强烈建议用表格而不是贴一堆截图。一个标准测试用例表长这样:
| 输入 | 预期输出 | 实际输出 | 是否一致 |
|---|---|---|---|
| 种子=42,名单5人 | 输出“C同学” | 输出“C同学” | 一致 |
| 种子=7,名单5人 | 输出“B同学” | 输出“B同学” | 一致 |
| 文件含3行成绩 | 新文件3行,空行被过滤 | 新文件3行 | 一致 |
| 票数=10,双窗口 | 两个窗口共卖出10张 | 窗口1卖出6,窗口2卖出4 | 一致 |
填表时要如实写,哪怕实际输出和预期不一致也要填进去,并在“总结”里解释原因。比如多线程实验,两个窗口交替卖票的次数比例不是固定的,实际输出和预期输出在顺序上可能不同,但总数正确。你把这个差异写出来,反而证明程序经过了充分测试。表格里的“一致”别全填“是”,运行结果有波动的实验留一个“顺序不同,总数一致”,比千篇一律的“是”更像真实测试记录。
5. 避坑与常见问题:编译报错、中文乱码和报告被退回的真实原因
下面这些坑来自大量课程作业里的高频翻车点,每一条我都按现象、原因、解决的顺序写,你对照自己的情况处理。
5.1 环境类翻车:编译不过、编码错乱、主类找不到
现象 1:在 IDE 里运行正常,换到命令行 javac 编译报错“编码 GBK 的不可映射字符”,或者输出里中文全是乱码。
原因:源码文件保存的是 UTF-8 编码,而 Windows 命令行默认用 GBK 去读;或者反过来,源码是 GBK 编码,你用 -encoding UTF-8 去编译。编码不匹配在中文提示、中文注释多的实验里特别明显。
解决:先确认源码文件本身的编码,用文本编辑器右下角能看到。然后 javac 编译时显式指定对应编码,我一般固定用javac -encoding UTF-8。同时把命令行窗口切到 UTF-8 编码再运行,Windows 下执行chcp 65001。两处都对齐,乱码基本消失。
现象 2:编译通过,但运行时提示“错误: 找不到或无法加载主类 Main”。
原因:你在源码目录里直接运行java Main,但 Main 类有 package 声明,必须用全限定类名。另一个可能是编译输出目录和-cp指定的目录不一致。
解决:回到项目根目录,用javac -encoding UTF-8 src/lab04_collection/*.java -d out编译,再用java -cp out lab04_collection.Main运行。类名必须带包路径,这是命令行 Java 新手最常见的错误。
现象 3:源码在自己机器上跑得正常,拷贝到老师机器上运行报 FileNotFoundException,提示找不到 txt 或 scores.txt。
原因:代码里用了绝对路径,比如new FileInputStream("C:/Users/xxx/Desktop/scores.txt"),换机器路径就失效。还有可能是相对路径基准不对,程序在 src 目录下运行时找的是 src 下的 scores.txt,而你实际把数据文件放在项目根目录。
解决:统一用相对路径,数据文件放在 Main 类所在目录的上一级,运行命令说明里写清楚“在项目根目录下执行”。如果你要提交整个压缩包,数据文件、源码、报告保持原来的目录层级不要动,压缩和解压后相对位置不变。
5.2 提交类翻车:报告截图无效、压缩包过脏、新旧 JDK 语法不兼容
现象 4:报告里的截图和代码运行结果不一致,比如代码里输出“第 1 张”截图却是“第 2 张”,老师标记“结果与代码不符”退回重交。
原因:截图是修改代码前截的,或者从网上找了类似的图,代码改动后没有重新跑一遍就交了上去。评分老师会挑一张截图手动复现,一旦发现数字对不上,整篇报告可信度就没了。
解决:代码每改一次,就重新截图一次,并保持命令行里的运行日期可见。截图命名按实验编号加序号,比如 lab06_3_result.png,替换掉旧图,避免文档里插入的还是上一轮的老图。
现象 5:压缩包 200MB,里面全是 out 目录、.idea 配置、class 文件,老师下载后解压都费劲,甚至直接退回。
原因:把整个工作区目录直接选中压缩,没清理编译产物和 IDE 配置。class 文件是编译生成的,只要源码在就能重新编译,提交它们毫无意义。
解决:提交前按第 2 章的目录结构整理,保留 src、docs、README,删掉 out 和 IDE 配置目录。压缩时选中 java-course-lab 文件夹整体压缩,让解压后第一层就是项目根目录,而不是套两层文件夹。
现象 6:你的代码用了 var 关键字、新版 switch 箭头语法,但老师机器上的 JDK 8 不支持,编译直接失败。
原因:JDK 10 之后才有 var,JDK 14 之后 switch 表达式才稳定。教学环境为了统一往往装 JDK 8,你的代码在自己电脑的 JDK 17 上没事,到老师机器上就是语法错误。
解决:写代码时先确认教学环境版本。如果拿不准,就避开新语法,变量老老实实写类型,switch 写成经典冒号形式。这类代码风格在课程作业里不会扣分,反而因为能兼容老环境,复跑成功率高。
6. 进阶用法:把课程实验改造成能写进简历的小项目
6.1 三步改造:以简易图书管理系统为例
前面的实验项目通常是单文件控制台程序,简历上写出来没分量。最常见的改造路线是把“文件 IO + 集合”的实验扩成一个简单三层结构的系统,改造方向很固定。
第一步,把存储层从文件换成数据库。实验里的 scores.txt 读写换成 JDBC 连接数据库,数据表设计两到三张:用户表、图书表、借阅记录表。存储层单独放一个包,界面和业务层不直接碰 JDBC 代码。
// 数据访问层只负责查询和写入,不处理业务判断 public class BookDao { public List<Book> findAll() throws SQLException { String sql = "SELECT id, name, price FROM book"; try (Connection conn = DriverManager.getConnection(DB_URL); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { List<Book> list = new ArrayList<>(); while (rs.next()) { list.add(new Book(rs.getInt("id"), rs.getString("name"), rs.getBigDecimal("price"))); } return list; } } }逻辑说明:PreparedStatement预编译防止 SQL 注入,try-with-resources保证连接自动关闭。这两点面试时经常被追问,比实验里的 BufferedReader 更贴近工程实践。改造时注意,JDBC 驱动 jar 包要放进项目并配置 classpath,源码里记得写Class.forName("com.mysql.cj.jdbc.Driver")或者确认驱动依赖已引入。
第二步,把业务判断从控制台里抽出来。比如借书操作要判断库存是否大于零、是否已借出,这些判断全部放到 Service 层,控制台只负责接收用户输入和显示结果。界面层换成 Java Swing 时,按钮事件里只调 Service 方法,不直接操作数据表。
第三步,加日志和异常处理。实验代码里大量的throws Exception要拆掉,换成具体的try-catch并记录到日志文件。日志不用引第三方库,java.util.logging足够撑起一个简历项目的基本观感。异常处理统一在 Service 层往外抛自定义异常,界面上捕获后弹提示框。
这三点做完,一个课程实验就成了“界面 + 业务 + 存储”三层结构的完整项目。你还可以把第 3 章里的随机种子技巧用起来:给测试用例固定种子,保证多次演示结果一致,这在项目验收演示时能避免“这次跑出不一样结果”的尴尬。从那以后,我每次整理课程作业都会强制走一遍固定流程:干净目录、命令行编译、删掉 out 再压缩、改完代码必须重新截图并更新报告。这套流程帮我少吃了很多次重交的苦。希望帮到你。
本文还有配套的精品资源,点击获取