导读:本期聚焦于梦乃创作的《如何用Java基础语法与ArrayList实现控制台版学生成绩管理系统?》,敬请观看详情。控制台程序看似简单,但要把学生成绩的录入、查询、修改、删除和排序做到可用,不少细节容易被忽略。本文不依赖任何框架,只用Java基础语法和ArrayList动态数组,逐步完成一个可运行的学生成绩管理系统。先梳理Student实体应包含哪些字段,再说明ArrayList相比普通数组在容量管理和增删操作上的优势。随后给出菜单循环、switch分支、Scanner输入与Double.parseDouble转换的完整实现,并重点演示按总分排序时Comparator接口的匿名内部类写法。之后补充输入校验、学号查重和删除时的索引边界处理。最后分析当前设计在并发、持久化方面的不足,以及替换为HashMap或数据库的演进方向。通篇代码可直接复制运行,适合Java初学者练习面向对象、集合和流程控制。

控制台版学生成绩管理系统,本质上是把一组学生对象放入内存集合中,通过命令行菜单完成增删改查和排序。这个项目对Java初学者非常友好:没有数据库连接,没有Web框架,只需要运用类与对象、Scanner输入、ArrayList动态数组、流程控制语句以及Comparator排序,就能形成一个可以反复运行的小工具。本文会从数据模型设计开始,逐步拆解菜单循环、成绩操作和输入容错,最后给出一些可扩展的思路。

如何用Java基础语法与ArrayList实现控制台版学生成绩管理系统?

一、先定义Student类,把成绩数据封装起来

做管理系统之前,第一步不是写菜单,而是想清楚要存储什么数据。一个学生至少包含学号、姓名、数学成绩、英语成绩和Java成绩。学号适合用String而不是int,因为学号可能存在前导零,而且String在后续比较和查找时更灵活。成绩统一使用double,可以兼容小数分,也为将来计算平均分、加权总分留下空间。

把这些字段放进Student类中,通过构造方法初始化,通过getter和setter访问。getTotal方法用来计算三科总分,toString方法方便在控制台直接打印对象信息。这个类不包含任何业务逻辑,只负责数据的承载和简单计算,符合Java面向对象中单一职责的基本思路。下面是一个可用的Student类,注意setter方法在修改成绩功能中会被调用。

public class Student {
    private String id;
    private String name;
    private double math;
    private double english;
    private double javaScore;

    public Student(String id, String name, double math, double english, double javaScore) {
        this.id = id;
        this.name = name;
        this.math = math;
        this.english = english;
        this.javaScore = javaScore;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getMath() {
        return math;
    }

    public double getEnglish() {
        return english;
    }

    public double getJavaScore() {
        return javaScore;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMath(double math) {
        this.math = math;
    }

    public void setEnglish(double english) {
        this.english = english;
    }

    public void setJavaScore(double javaScore) {
        this.javaScore = javaScore;
    }

    public double getTotal() {
        return math + english + javaScore;
    }

    @Override
    public String toString() {
        return "学号:" + id + ",姓名:" + name + ",数学:" + math +
               ",英语:" + english + ",Java:" + javaScore + ",总分:" + getTotal();
    }
}

与普通数组相比,ArrayList的优势在于容量可以动态变化。学生数量在运行前并不确定,如果用String[]或Student[],要么一开始就指定一个可能浪费的固定长度,要么在添加时频繁复制数组。ArrayList在内部封装了扩容机制,开发者只需要调用add、remove、get、size、sort等方法,代码更简洁,也更贴近真实业务中的集合操作。

二、用while循环和switch搭建菜单主体

控制台程序的核心交互是菜单循环。程序启动后打印可选项,用户输入数字后进入对应分支,执行完再回到菜单,直到用户选择退出。Java里可以用while(true)配合switch实现。Scanner负责从标准输入读取字符串,菜单选择也使用nextLine读取,避免nextInt留下换行符导致后续读取被跳过的问题。

主类StudentManager中维护一个静态的ArrayList<Student>作为全局数据源,同时维护一个静态Scanner对象。静态成员可以让多个方法直接访问,不需要传递参数。菜单方法printMenu只负责输出提示,main方法负责分流。这样做的好处是每个功能方法只处理自己的逻辑,结构清晰。下面给出主类和菜单循环的骨架,后续的功能方法会逐步补充进这个类。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;

public class StudentManager {
    private static ArrayList<Student> students = new ArrayList<>();
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        while (true) {
            printMenu();
            String choice = scanner.nextLine();
            switch (choice) {
                case "1":
                    addStudent();
                    break;
                case "2":
                    listStudents();
                    break;
                case "3":
                    updateStudent();
                    break;
                case "4":
                    deleteStudent();
                    break;
                case "5":
                    sortByTotal();
                    break;
                case "6":
                    System.out.println("程序已退出");
                    return;
                default:
                    System.out.println("请输入1到6之间的数字");
            }
        }
    }

    private static void printMenu() {
        System.out.println("========= 学生成绩管理系统 =========");
        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.print("请选择操作:");
    }
}

需要注意的是,菜单循环本身不会自动处理异常。如果用户输入了非数字,switch会直接进入default分支,不会导致崩溃;但成绩读取时如果用户输入abc,就可能在Double.parseDouble处抛出NumberFormatException。所以成绩输入必须单独做容错,这一点会在下一节展开。

三、实现添加、查看、修改、删除和排序

添加学生时,先检查学号是否已经存在。因为ArrayList允许重复元素,但学号在业务上应该是唯一标识。遍历students集合,比较getId,如果相同就提示添加失败。成绩输入通过一个readDouble方法循环读取,直到用户输入合法的数字为止。这样即使误输入字母,程序也不会中断,而是提示重新输入。

    private static void addStudent() {
        System.out.print("请输入学号:");
        String id = scanner.nextLine();
        for (Student s : students) {
            if (s.getId().equals(id)) {
                System.out.println("该学号已存在,添加失败");
                return;
            }
        }
        System.out.print("请输入姓名:");
        String name = scanner.nextLine();
        System.out.print("请输入数学成绩:");
        double math = readDouble();
        System.out.print("请输入英语成绩:");
        double english = readDouble();
        System.out.print("请输入Java成绩:");
        double javaScore = readDouble();

        students.add(new Student(id, name, math, english, javaScore));
        System.out.println("添加成功");
    }

    private static double readDouble() {
        while (true) {
            try {
                return Double.parseDouble(scanner.nextLine());
            } catch (NumberFormatException e) {
                System.out.print("成绩必须是数字,请重新输入:");
            }
        }
    }

查看全部学生非常简单,先判断students.isEmpty,空列表时直接提示,避免输出空行。随后使用增强for循环打印每个Student对象,此时会自动调用Student的toString方法。修改成绩则需要先根据学号找到索引,再让用户逐项输入新值。为了降低操作成本,这里采用回车保持原值的策略,只在实际输入非空字符串时才更新姓名,只在实际输入数字时才更新对应成绩。findIndexById返回-1表示未找到,这样删除和修改都可以复用同一个查找方法。

    private static void listStudents() {
        if (students.isEmpty()) {
            System.out.println("当前没有学生数据");
            return;
        }
        for (Student s : students) {
            System.out.println(s);
        }
    }

    private static void updateStudent() {
        System.out.print("请输入要修改的学生学号:");
        String id = scanner.nextLine();
        int index = findIndexById(id);
        if (index == -1) {
            System.out.println("未找到该学生");
            return;
        }
        Student s = students.get(index);
        System.out.println("当前信息:" + s);
        System.out.print("请输入新的姓名(回车保持原值):");
        String name = scanner.nextLine();
        if (!name.trim().isEmpty()) {
            s.setName(name);
        }
        s.setMath(readUpdatedScore("数学", s.getMath()));
        s.setEnglish(readUpdatedScore("英语", s.getEnglish()));
        s.setJavaScore(readUpdatedScore("Java", s.getJavaScore()));
        System.out.println("修改成功");
    }

    private static double readUpdatedScore(String subject, double oldScore) {
        while (true) {
            System.out.print("请输入新的" + subject + "成绩(回车保持" + oldScore + "):");
            String input = scanner.nextLine();
            if (input.trim().isEmpty()) {
                return oldScore;
            }
            try {
                return Double.parseDouble(input);
            } catch (NumberFormatException e) {
                System.out.println("成绩格式不正确,请重新输入");
            }
        }
    }

    private static int findIndexById(String id) {
        for (int i = 0; i < students.size(); i++) {
            if (students.get(i).getId().equals(id)) {
                return i;
            }
        }
        return -1;
    }

删除操作是ArrayList最直接的remove(int index)调用。因为remove会将被删除元素后面的所有元素向前移动一位,所以如果使用遍历删除,必须注意索引变化。这里先查找索引,再删除,不会出现漏删或越界。删除前可以打印被删除对象的信息,便于确认操作结果。

    private static void deleteStudent() {
        System.out.print("请输入要删除的学生学号:");
        String id = scanner.nextLine();
        int index = findIndexById(id);
        if (index == -1) {
            System.out.println("未找到该学生");
            return;
        }
        Student removed = students.remove(index);
        System.out.println("已删除:" + removed.getName());
    }

按总分排序使用List接口提供的sort方法,传入一个Comparator实现。匿名内部类中compare方法返回Double.compare(s2.getTotal(), s1.getTotal()),注意参数顺序是s2在前、s1在后,这样得到从高到低的降序排列。如果希望总成绩相同时按学号升序,可以在compare中追加一个二级判断。排序完成后调用listStudents展示结果。

    private static void sortByTotal() {
        students.sort(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                if (Double.compare(s2.getTotal(), s1.getTotal()) != 0) {
                    return Double.compare(s2.getTotal(), s1.getTotal());
                }
                return s1.getId().compareTo(s2.getId());
            }
        });
        System.out.println("已按总分从高到低排序");
        listStudents();
    }

这五个功能合起来已经构成一个可运行的控制台程序。将Student类和StudentManager类放在同一目录下,先编译Student.java再编译StudentManager.java,或者直接使用IDE运行,即可在命令行中体验完整的流程。建议读者不要只看代码,而是亲手输入并故意制造几次错误输入,观察程序是否能继续运行,这样对异常处理和边界条件的理解会更深刻。

四、常见错误与演进方向

初学者在这个项目中容易遇到三类问题。第一类是Scanner混用nextInt和nextLine,导致读取菜单选项后多出一个空行,后续的姓名或学号被直接跳过。统一使用nextLine并手动parse可以避免这个坑。第二类是成绩输入未做异常捕获,用户输入非数字后程序直接抛异常退出。第三类是删除时使用for循环正向遍历,边遍历边删除,容易跳过连续满足条件的元素。本文先用findIndexById定位再删除,规避了这一问题。

从项目演进角度看,当学生数量变大时,使用ArrayList按学号查找的时间复杂度是O(n)。如果希望更快,可以引入HashMap<String, Student>,以学号为键、学生对象为值,查找接近O(1)。但HashMap本身不保证顺序,如果需要按添加顺序展示,还要配合LinkedHashMap或用ArrayList保存顺序。另一个方向是持久化,当前数据在程序退出后就丢失。可以把学生信息写入文本文件、CSV或使用Serializable序列化,也可以接入SQLite、MySQL等数据库,让系统成为真正的数据管理工具。

如果继续用控制台版本练习,还可以增加按单科成绩统计最高分、最低分和平均分,或者加入学分权重计算加权总分。这些功能不需要改变现有结构,只需在StudentManager中增加方法。通过这个项目把类、集合、异常和接口串起来,比单纯记忆语法要有效得多。

Java基础语法ArrayList学生成绩管理系统修改时间:2026-10-07 00:17:45

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1007/66646.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。