这套系统采用了经典的 MVC (Model-View-Controller) 设计模式,代码结构清晰,易于理解和扩展,它使用 控制台 作为用户界面,通过 文件 (I/O) 来持久化数据,无需依赖任何数据库,非常适合学习和作为课程设计项目。

- 学生信息管理:添加、删除、修改、查询学生信息(学号、姓名、性别)。
- 成绩管理:为每个学生添加多门课程的成绩(课程名、分数)。
- 数据持久化:所有学生信息和成绩数据会自动保存到
students.dat文件中,程序关闭后重新打开,数据依然存在。 - 统计功能:
- 计算单个学生的总分和平均分。
- 计算指定课程的全班平均分、最高分和最低分。
- 界面友好:提供清晰的菜单导航,操作简单。
项目结构
为了方便理解,我们将代码组织在几个不同的包中:
StudentManagementSystem/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── model/ // Model 层:数据模型
│ │ │ │ ├── Course.java
│ │ │ │ ├── Student.java
│ │ │ │ └── StudentManagementSystem.java (核心业务逻辑)
│ │ │ ├── view/ // View 层:用户界面
│ │ │ │ └── MainView.java
│ │ │ ├── controller/ // Controller 层:控制逻辑
│ │ │ │ └── MainController.java
│ │ │ └── Main.java // 程序入口
│ │ └── resources/
│ └── test/
源代码详解
以下是每个文件的完整源代码。
Model 层
model/Student.java
学生实体类,包含学生的基本信息和成绩列表。
package model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Student implements Serializable {
private String studentId;
private String name;
private String gender;
private List<Course> courses;
public Student(String studentId, String name, String gender) {
this.studentId = studentId;
this.name = name;
this.gender = gender;
this.courses = new ArrayList<>();
}
// Getters and Setters
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public List<Course> getCourses() {
return courses;
}
public void addCourse(Course course) {
this.courses.add(course);
}
public void removeCourse(String courseName) {
this.courses.removeIf(c -> c.getCourseName().equals(courseName));
}
public Course findCourse(String courseName) {
for (Course c : courses) {
if (c.getCourseName().equals(courseName)) {
return c;
}
}
return null;
}
public double getTotalScore() {
return courses.stream().mapToDouble(Course::getScore).sum();
}
public double getAverageScore() {
if (courses.isEmpty()) {
return 0.0;
}
return getTotalScore() / courses.size();
}
@Override
public String toString() {
return "Student{" +
"studentId='" + studentId + '\'' +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", courses=" + courses +
'}';
}
}
model/Course.java
课程实体类,包含课程名和分数。

package model;
import java.io.Serializable;
public class Course implements Serializable {
private String courseName;
private double score;
public Course(String courseName, double score) {
this.courseName = courseName;
this.score = score;
}
// Getters and Setters
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Course{" +
"courseName='" + courseName + '\'' +
", score=" + score +
'}';
}
}
model/StudentManagementSystem.java
核心业务逻辑类,负责管理所有学生和文件读写操作。
package model;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StudentManagementSystem implements Serializable {
private List<Student> students;
private static final String FILE_NAME = "students.dat";
public StudentManagementSystem() {
this.students = new ArrayList<>();
loadData();
}
public void addStudent(Student student) {
students.add(student);
saveData();
}
public void removeStudent(String studentId) {
students.removeIf(s -> s.getStudentId().equals(studentId));
saveData();
}
public Student findStudent(String studentId) {
for (Student s : students) {
if (s.getStudentId().equals(studentId)) {
return s;
}
}
return null;
}
public List<Student> getAllStudents() {
return students;
}
public void updateStudent(Student updatedStudent) {
for (int i = 0; i < students.size(); i++) {
if (students.get(i).getStudentId().equals(updatedStudent.getStudentId())) {
students.set(i, updatedStudent);
saveData();
return;
}
}
}
// 统计功能
public double calculateCourseAverage(String courseName) {
List<Double> scores = students.stream()
.map(s -> s.findCourse(courseName))
.filter(c -> c != null)
.map(Course::getScore)
.collect(Collectors.toList());
if (scores.isEmpty()) return 0.0;
return scores.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
}
public double calculateCourseMax(String courseName) {
return students.stream()
.map(s -> s.findCourse(courseName))
.filter(c -> c != null)
.mapToDouble(Course::getScore)
.max().orElse(0.0);
}
public double calculateCourseMin(String courseName) {
return students.stream()
.map(s -> s.findCourse(courseName))
.filter(c -> c != null)
.mapToDouble(Course::getScore)
.min().orElse(0.0);
}
// 文件操作
private void saveData() {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_NAME))) {
oos.writeObject(students);
} catch (IOException e) {
System.err.println("Error saving data: " + e.getMessage());
}
}
@SuppressWarnings("unchecked")
private void loadData() {
File file = new File(FILE_NAME);
if (file.exists()) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) {
students = (List<Student>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
System.err.println("Error loading data: " + e.getMessage());
students = new ArrayList<>(); // 如果加载失败,初始化一个空列表
}
}
}
}
View 层
view/MainView.java
负责与用户交互,显示菜单和接收输入。
package view;
import model.Course;
import model.Student;
import model.StudentManagementSystem;
import java.util.List;
import java.util.Scanner;
public class MainView {
private Scanner scanner;
private StudentManagementSystem sms;
public MainView(StudentManagementSystem sms) {
this.sms = sms;
this.scanner = new Scanner(System.in);
}
public void showMenu() {
while (true) {
System.out.println("\n========== 学生成绩管理系统 ==========");
System.out.println("1. 添加学生");
System.out.println("2. 删除学生");
System.out.println("3. 修改学生信息");
System.out.println("4. 查询学生信息");
System.out.println("5. 添加/修改学生成绩");
System.out.println("6. 计算学生总分和平均分");
System.out.println("7. 课程统计(平均分、最高分、最低分)");
System.out.println("8. 显示所有学生");
System.out.println("0. 退出系统");
System.out.println("====================================");
System.out.print("请选择操作: ");
int choice;
try {
choice = Integer.parseInt(scanner.nextLine());
} catch (NumberFormatException e) {
System.out.println("输入无效,请输入数字!");
continue;
}
switch (choice) {
case 1:
addStudent();
break;
case 2:
removeStudent();
break;
case 3:
updateStudent();
break;
case 4:
findStudent();
break;
case 5:
addOrUpdateScore();
break;
case 6:
calculateStudentStats();
break;
case 7:
calculateCourseStats();
break;
case 8:
displayAllStudents();
break;
case 0:
System.out.println("感谢使用,再见!");
return;
default:
System.out.println("无效的选择,请重新输入!");
}
}
}
private void addStudent() {
System.out.println("--- 添加学生 ---");
System.out.print("请输入学号: ");
String id = scanner.nextLine();
if (sms.findStudent(id) != null) {
System.out.println("该学号已存在!");
return;
}
System.out.print("请输入姓名: ");
String name = scanner.nextLine();
System.out.print("请输入性别: ");
String gender = scanner.nextLine();
sms.addStudent(new Student(id, name, gender));
System.out.println("学生添加成功!");
}
private void removeStudent() {
System.out.println("--- 删除学生 ---");
System.out.print("请输入要删除的学生学号: ");
String id = scanner.nextLine();
if (sms.findStudent(id) != null) {
sms.removeStudent(id);
System.out.println("学生删除成功!");
} else {
System.out.println("未找到该学号的学生!");
}
}
private void updateStudent() {
System.out.println("--- 修改学生信息 ---");
System.out.print("请输入要修改的学生学号: ");
String id = scanner.nextLine();
Student student = sms.findStudent(id);
if (student == null) {
System.out.println("未找到该学号的学生!");
return;
}
System.out.println("当前信息: " + student);
System.out.print("请输入新姓名 (回车保持原值): ");
String name = scanner.nextLine();
if (!name.isEmpty()) student.setName(name);
System.out.print("请输入新性别 (回车保持原值): ");
String gender = scanner.nextLine();
if (!gender.isEmpty()) student.setGender(gender);
sms.updateStudent(student);
System.out.println("学生信息更新成功!");
}
private void findStudent() {
System.out.println("--- 查询学生信息 ---");
System.out.print("请输入要查询的学生学号: ");
String id = scanner.nextLine();
Student student = sms.findStudent(id);
if (student != null) {
System.out.println(student);
} else {
System.out.println("未找到该学号的学生!");
}
}
private void addOrUpdateScore() {
System.out.println("--- 添加/修改学生成绩 ---");
System.out.print("请输入学生学号: ");
String studentId = scanner.nextLine();
Student student = sms.findStudent(studentId);
if (student == null) {
System.out.println("未找到该学号的学生!");
return;
}
System.out.print("请输入课程名: ");
String courseName = scanner.nextLine();
System.out.print("请输入分数: ");
double score;
try {
score = Double.parseDouble(scanner.nextLine());
} catch (NumberFormatException e) {
System.out.println("分数格式错误!");
return;
}
Course course = student.findCourse(courseName);
if (course != null) {
course.setScore(score);
System.out.println("成绩更新成功!");
} else {
student.addCourse(new Course(courseName, score));
System.out.println("成绩添加成功!");
}
sms.updateStudent(student); // 保存更新
}
private void calculateStudentStats() {
System.out.println("--- 计算学生总分和平均分 ---");
System.out.print("请输入学生学号: ");
String id = scanner.nextLine();
Student student = sms.findStudent(id);
if (student != null) {
System.out.printf("学生 %s 的总分: %.2f, 平均分: %.2f\n",
student.getName(), student.getTotalScore(), student.getAverageScore());
} else {
System.out.println("未找到该学号的学生!");
}
}
private void calculateCourseStats() {
System.out.println("--- 课程统计 ---");
System.out.print("请输入课程名: ");
String courseName = scanner.nextLine();
double avg = sms.calculateCourseAverage(courseName);
double max = sms.calculateCourseMax(courseName);
double min = sms.calculateCourseMin(courseName);
System.out.printf("课程 '%s' 的统计结果:\n", courseName);
System.out.printf("平均分: %.2f, 最高分: %.2f, 最低分: %.2f\n", avg, max, min);
}
private void displayAllStudents() {
System.out.println("--- 所有学生信息 ---");
List<Student> students = sms.getAllStudents();
if (students.isEmpty()) {
System.out.println("当前没有学生信息。");
} else {
for (Student s : students) {
System.out.println(s);
}
}
}
}
Controller 层
controller/MainController.java
连接 Model 和 View,是整个应用的协调者。
package controller;
import model.StudentManagementSystem;
import view.MainView;
public class MainController {
public static void main(String[] args) {
// 1. 创建 Model 实例,它会自动加载数据
StudentManagementSystem sms = new StudentManagementSystem();
// 2. 创建 View 实例,并将 Model 传递给它
MainView view = new MainView(sms);
// 3. 启动用户界面
view.showMenu();
}
}
如何运行
-
环境准备:确保您的电脑上已安装 JDK (Java Development Kit) 和集成开发环境,如 IntelliJ IDEA 或 Eclipse。
(图片来源网络,侵删) -
创建项目:
- 在您的 IDE 中创建一个新的 Java 项目。
- 创建如上所示的包结构:
model,view,controller。
-
复制代码:
- 将上述
Student.java,Course.java,StudentManagementSystem.java代码分别复制到model包中对应的文件里。 - 将
MainView.java代码复制到view包中。 - 将
MainController.java代码复制到controller包中。注意:MainController.java中的public class MainController应该改为public class Main,或者直接把main方法放在MainView或StudentManagementSystem中,为了清晰,我们这里将其作为控制器,并命名为Main,以下是修正后的controller/Main.java:
package controller; import model.StudentManagementSystem; import view.MainView; public class Main { // 将类名改为 Main public static void main(String[] args) { // 1. 创建 Model 实例,它会自动加载数据 StudentManagementSystem sms = new StudentManagementSystem(); // 2. 创建 View 实例,并将 Model 传递给它 MainView view = new MainView(sms); // 3. 启动用户界面 view.showMenu(); } } - 将上述
-
编译和运行:
- 在 IDE 中找到
controller.Main这个类,右键点击并选择 "Run 'Main.main()'"。 - 程序启动后,您将看到一个命令行菜单,可以通过输入数字来选择不同的功能。
- 在 IDE 中找到
扩展建议
这个项目已经具备了基本功能,您还可以在此基础上进行扩展,
- 图形用户界面:使用 Java Swing 或 JavaFX 开发一个图形界面,替代控制台界面,体验会更好。
- 数据库存储:将文件存储方式替换为 MySQL、PostgreSQL 等关系型数据库,或者 MongoDB 等 NoSQL 数据库,这对于处理大量数据更为高效和稳定。
- 更多统计功能:增加按成绩排序、查询不及格学生、生成成绩单等功能。
- 用户权限管理:增加管理员和普通用户的区分,不同权限的用户拥有不同的操作范围。
- 日志记录:增加日志功能,记录所有关键操作,便于追踪和排查问题。
