2020-05-08

学生管理系统项目

1、学生管理系统项目

尝试完成以下功能

    实体类:

        学生类:

            id, 姓名,年龄,性别,成绩

    需要使用数组保存学生信息

        Student[] allStu

    需要完成的方法

        1. 根据学生的ID,找到对应的学生对象【完成】

        2. 完成方法,添加新学生

        3. 完成方法,删除指定ID的学生

        4. 完成方法,展示数组中所有的学生信息

        5. 根据学生成绩,完成降序排序

1.1包结构划分

包名规范:

    1. 所有的单词全部小写

    2. 不同的单词直接使用 . 隔开

    3. 包结构其实对应的就是一个真实的目录结构

包结构的使用是为了在开发中让代码结构更加明确,更好管理,会慢慢接触到MVC设计模式。

    MVC ==> Model Viewer Controller

目前学生管理系统需要的包【目前功能所需】

    实体类 : 所有的实体类都会在一个包下

    管理类 : 需要一个管理类来管理学生操作【核心】,需要一个包

    主方法类 : 主方法

    测试类: 测试功能,养成习惯,对于代码中的功能,写一个测试一个,今天会到用@Test

包名:

    com.qfedu.student.system

        --| entity 实体类包

       --| manager  管理类包

        --| mainproject 主方法所在包

        --| testsystem 测试类

1.2学生实体类

package com.qfedu.student.system.entity;

/**

* 学生实体类

*

* @author Anonymous

*

*/

public class Student {

    private int id;

    private String name;

    private int age;

    private char gender;

    private int score;

    public Student() {}

    public Student(int id, String name, int age, char gender, int score) {

        super();

        this.id = id;

        this.name = name;

        this.age = age;

        this.gender = gender;

        this.score = score;

    }

    public int getId() {

        return id;

    }

    public void setId(int id) {

        this.id = id;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public char getGender() {

        return gender;

    }

    public void setGender(char gender) {

        this.gender = gender;

    }

    public int getScore() {

        return score;

    }

    public void setScore(int score) {

        this.score = score;

    }

    /**

    * 使用System.out.println打印展示Student类对象时

    * 是直接自动调用toString方法,展示该方法返回String字符串内容

    */

    @Override

    public String toString() {

        return "Student [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + ", score=" + score

+ "]";

    }

}

1.3管理类功能分析

管理类:

    1. 数据的保存

    2. 数据处理

        CRUD 增删改查

数据的保存

    明确使用的是一个Student类型的数据

    Student[] allStus;

    问题:

        成员变量

            使用一个成员变量数组来保存对应的数据,所有的内容都依赖于类对象的操作来完成,而且每一个管理类对象中保存的数据都是不一样的。

            目前的不一样,是为了更好的复用性,后来的数据一样,是为了数据的统一性

当前管理类

    功能后期是考虑复用的!!!

    不管是数据的存储方式,数据的处理方式,都要需要考虑满足多种情况,多种方式。

1.4管理类构造方法

因为当前管理类内的成员变量是一个数组,当前构造方法需要对于保存学生信息的数组进行初始化操作。

     传入参数是一个数组容量 

传入一个数组,操作性,包括安全性都是存在一定的隐患。操作性较差,用户需要提供真实管理数据的空间,繁琐,引用指向有可能导致数据丢失。

传入一个数组容量,用户操作自由度更高!!!方便!!!快捷!!!省心省事!!!

要求传入的参数是一个数组容量,有没有要求???

    1. int

    2. 非负

    3. int类型的最大值

    【补充】Java中数组容量范围是在int范围以内,要求数组容量不得超出int范围Integer.MAX_VALUE - 8 为什么-8后面解释!!!

构造方法这里提供两种

    1. 无参数构造方法

        用户不用指定容量,我们给予用户一个初始化容量使用

    2. 有参数构造方法

        用户指定底层数组容量,要求数据在合理范围以内

1.5构造方法完成和成员变量补充

package com.qfedu.student.system.manager;

import com.qfedu.student.system.entity.Student;

public class StudentManager {

    /**

    * 私有化保存学生信息的数组,对外不能公开,有且只针对于当前管理类使用

    * 初始化为null

    */

    private Student[] allStus = null;

    /**

    * DEFAULT_CAPACITY 默认容量,这里是一个带有名字的常量

    */

    private static final int DEFAULT_CAPACITY = 10;

    /**

    * 数组最大容量,是int类型最大值 - 8

    * -8等我给你讲

    */

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**

    * 无参数构造方法,但是需要创建底层保存学生数据的Student数组,因为当前数组

    * 不存在,指向为null

    *

    */

    public StudentManager() {

        allStus = new Student[DEFAULT_CAPACITY];

    }

    /**

    * 用户指定初始化容量,但是要求初始化容量在合理范围以内,不能小于0 ,不能

    * 大于数组的最大值,MAX_ARRAY_SIZE

    *

    * @param initCapacity 用户指定的初始化容量

    */

    public StudentManager(int initCapacity) {

        if (initCapacity < 0 || initCapacity > MAX_ARRAY_SIZE) {

            System.out.println("Input Parameter is Invalid!");

            /* 异常抛出!!! 补充该知识点 暂时留下一个 System.exit(0) 退出程序*/

            System.exit(0);

        }

        allStus = new Student[initCapacity];

    }

}

1.6增删改查方法实习

1.6.1增【重点】

分析:

    权限修饰符:

    public 

    不需要static修饰:

    返回值类型:

        boolean

        添加成功返回true,添加失败返回false

    方法名:

         add (添加)

     形式参数列表:

         Student student

方法声明:

    public boolean add(Student stu)

这里需要采用尾插法数据存入,这里需要一个计数器

    int类型变量

成员变量:

    可以保证每一个StudentManager对象中存储的内容都是独立,是根据当前数组中存储数据的容量来确定

/**

* 当前方法是添加学生类对象到StudentManager中,保存到底层的Student类型数组     

*                                                     

* @param stu Student类对象                               

* @return 添加成功返回true,失败返回false                       

*/                                                   

public boolean add(Student stu) {                     

    allStus[size] = stu;                               

    size += 1;                                         

    return true;                                       

}

1.6.2grow方法,底层数组容量扩容方法【核心】

流程

    1. 获取原数组容量

    2. 计算得到新数组容量

    3. 创建新数组

    4. 迁移数据

    5. 保存新数组地址

方法分析:

    权限修饰符:

        private 核心操作,主要是在类内使用,类外不能调用当前方法。

    不需要static修饰:

    返回值类型:

        void 当前方法不需要返回值

    方法名:

        grow

    形式参数列表:

        要求最小容量

        为了保证add操作在合理的容量范围以内(MAX_ARRAY_SIZE)操作成功,这里要求通过add方法告知grow方法,最小要求容量扩容到多少?

        需要考虑一些极端情况:

            1. 添加多个,超出了grow增加的范围

            2. 原数组容量为1,扩容之后不够用

方法声明:

    private void grow(int minCapacity);

/**

* 类内私有化方法,用于在添加元素过程中,出现当前底层数组容量不足的情况下 

* 对底层数组进行扩容操作,满足使用要求                                   

*                                                         

* @param minCapacity 添加操作要求的最小容量                         

*/                                                       

private void grow(int minCapacity) {                       

    // 1. 获取原数组容量                                         

    int oldCapacity = allStus.length;                     

    // 2. 计算得到新数组容量,新数组容量大约是原数组容量的1.5倍                         int newCapacity = oldCapacity + oldCapacity / 2;       

    // 3. 判断新数组容量是否满足最小容量要求                               

    if (minCapacity > newCapacity) {                       

        newCapacity = minCapacity;                         

    }                                                     

    // 4. 判断当前容量是否超出了MAX_ARRAY_SIZE                       

    if (newCapacity > MAX_ARRAY_SIZE) {                   

    /* 这里需要一个异常处理,目前我们采用程序退出 */                       

        System.exit(0);                                   

    }                                                     

     // 5. 创建新数组                                           

    Student[] temp = new Student[newCapacity];             

    // 6. 数据拷贝                                             

    for (int i = 0; i < oldCapacity; i++) {               

        temp[i] = allStus[i];                             

    }                                                     

    // 7. 使用allStus保存新数组首地址                               

    allStus = temp;                                       

}

1.6.3删【重点】

方法分析:

    权限修饰符:

        public 

    不需要static修饰:

返回值类型:

    boolean 删除成功返回true,删除失败返回false

方法名:

    remove 移除

形式参数列表:

    int id

方法声明:

    public boolean remove(int id)

流程:

    1. 根据ID找出对应的学生对象在数组中的下标位置

    2. 根据下标位置删除元素,从删除位置开始,之后的元素整体先前移动

    3. 最后一个原本存在数据的位置赋值为null

    4. size 有效元素个数 -= 1

/**

* 根据用户指定的ID号,删除对应学生类对象                           

*                                               

* @param id 指定的学生ID好                             

* @return 删除成功返回true,删除失败返回false                 

*/                                               

public boolean remove(int id) {                   

    int index = -1;                               

    // 遍历数组的终止条件为size,有效元素个数                     

    for (int i = 0; i < size; i++) {             

        if (id == allStus[i].getId()) {           

            index = i;                           

            break;                               

        }                                         

    }                                             

    /*                                           

    *  以上代码循环结束,如果index的值为-1,证明没有找到对应的元素         

    *  当前方法无法进行删除操作,返回false                     

    */                                           

    if (-1 == index) {                           

        System.out.println("Not Found!");         

        return false;                             

    }                                             

     /*                                           

    *  如果index值不是-1,表示找到了对应需要删除的元素,进行删除操作      

    *                                           

    *  假设原数组容量10,有效元素个数为10,删除下标为5的元素             

    *  数组[5] = 数组[6];                       

    *  数组[6] = 数组[7];                       

    *  数组[7] = 数组[8];                       

    *  数组[8] = 数组[9];                       

    *  数组[9] = null;                         

    *                                           

    *  数组[i] = 数组[i + 1];                   

    */                                           

    for (int i = index; i < size - 1; i++) {     

        allStus[i] = allStus[i + 1];             

    }                                             

    // 原本最后一个有效元素位置赋值为null                       

    allStus[size - 1] = null;                     

    // 有效元素个数 - 1                                 

    size -= 1;                                   

    return true;                                 

}

1.6.4 查 根据学生的ID,找到对应的学生对象【重点】

方法分析:

    权限修饰符

        public  

    不需要static修饰

    返回值类型:

        Student学生类对象

    方法名:

        get 获取

    形式参数列表:

        int id

方法声明:

    public Student get(int id);

/**

* 根据指定的ID获取对应的Student类对象                   

*                                           

* @param id 指定的ID号                         

* @return 返回对应的Student类对象, 如果没有找到,返回null   

*/                                         

public Student get(int id) {                 

    int index = findIndexById(id);           

    return index > -1 ? allStus[index] : null;

}

1.6.5 补充方法,根据ID获取对应下标位置

方法分析:

    权限修饰符:

        private √ 给内部其他方法使用的一个功能,不需要对外

    不需要static修饰

    返回值类型:

        int 需要的是一个下标,为int类型

    方法名:

        findIndexById

    形式参数列表:

        int id

方法声明:

    private int findIndexById(int id);

/**

* 类内私有化方法,用于根据指定ID获取对应的下标位置,提供给其他方法使用  *                                                       

* @param id 指定ID号                                       

* @return 返回值是对应的下标位置,返回值大于等于0 表示找到对应元素,返回-1没有找到         

*/                                                       

private int findIndexById(int id) {                       

    int index = -1;                                       

    for (int i = 0; i < size; i++) {                     

        if (id == allStus[i].getId()) {                   

            index = i;                                   

            break;                                       

        }                                                 

    }                                                     

    return index;                                         

}

1.6.6改

需求:

    真实修改数组中保存的学生对象数据。

    需要找到对应学生对象,修改其中指定的数据

方法分析:

    权限修饰符:

        public

    不需要static修饰

    返回值类型:

        boolean √ 检测方法运行状态,如果出现问题,返回false

    方法名:

        modify

    形式参数列表:

        int id

    方法声明:

        public boolean modify(int id)

static补充

    1. static修饰静态成员变量的共享性和持久性

    2. static修饰静态代码块的加载性,和初始化操作

    3. static修饰静态成员方法操作的便捷性和独立性

/**

* 根据用户指定的ID号,修改对应学生的信息                                 

*                                                         

* @param id 用户指定的ID号                                       

* @return 方法运行成功返回true,如果修改无法完成返回false                 

*/                                                         

public boolean modify(int id) {                             

    // 通过类内其他成员方法获取对应ID的学生类对象                               

    Student stu = get(id);                                 

    // 没有对应的学生类对象                                           

    if (null == stu) {                                     

        System.out.println("Not Found");                   

        return false;                                       

    }                                                       

    // 类似于点菜系统,需要完成修改操作                                     

    Scanner sc = new Scanner(System.in);                   

    int choose = 0;                                         

    while (choose != 5) {                                   

        System.out.println("ID: " + stu.getId());           

        System.out.println("Name: " + stu.getName());       

        System.out.println("Age: " + stu.getAge());         

        System.out.println("Gender: " + stu.getGender());   

        System.out.println("Score: " + stu.getScore());     


        System.out.println("1. 修改学生姓名");                   

        System.out.println("2. 修改学生年龄");                   

        System.out.println("3. 修改学生性别");                   

        System.out.println("4. 修改学生成绩");                   

        System.out.println("5. 退出");                       


        choose = sc.nextInt();                             

        // 1\n ==> 1 程序中剩余\n                               

        sc.nextLine();                                     


        switch (choose) {                                   

            case 1:                                             

                System.out.println("请输入学生的姓名:");               

                String name = sc.nextLine();                   

                stu.setName(name);                             

                break;                                         

        case 2:                                             

            System.out.println("请输入学生的年龄:");               

            int age = sc.nextInt();                         

            stu.setAge(age);;                               

            break;                                         

        case 3:                                             

            System.out.println("请输入学生的性别:");               

            char gender = sc.nextLine().charAt(0);         

            stu.setGender(gender);                         

            break;                                         

        case 4:                                             

            System.out.println("请输入学生的成绩:");               

            int score = sc.nextInt();                       

            stu.setScore(score);                           

            break;                                         

        case 5:                                             

            System.out.println("保存退出");                     

            break;                                         

        default:                                           

            System.out.println("选择错误,请重新选择");               

            break;                                         

        }                                                   

    }                                                       

    return true;                                           

}

1.6.7排序

需求:

    根据学生的成绩,降序排序

方法分析:

    权限修饰符:

        public

    不需要static修饰:

    返回值类型:

        void

    方法名:

        scoreSortDesc

形式参数列表:

        不需要参数

方法声明:

    public void scoreSortDesc()

/**

* 按照成绩降序排序的算法                                               

*/                                                                 

public void scoreSortDesc() {                                       

    /*                                                             

    * 排序算法操作不能在原数据数组中进行直接操作,需要另外准备           

    * 一个用于排序的临时数组,这里就涉及到一个数据拷贝过程。             

    */                                                             

    Student[] sortTemp = new Student[size];                         

    for (int i = 0; i < sortTemp.length; i++) {                     

        sortTemp[i] = allStus[i];                                   

    }                                                               

    for (int i = 0; i < sortTemp.length - 1; i++) {                 

        // 找出极值                                                 

        int index = i;                                             

        for (int j = i + 1; j < sortTemp.length; j++) {             

            // 按照成绩降序排序                                             

            if (sortTemp[index].getScore() > sortTemp[j].getScore()) {

                index = j;                                         

            }                                                       

        }                                                           


        // 交换位置                                                 

        if (index != i) {                                           

            Student stu = sortTemp[index];                         

            sortTemp[index] = sortTemp[i];                         

            sortTemp[i] = stu;                                     

        }                                                           

    }                                                               


    for (int i = 0; i < sortTemp.length; i++) {                     

        System.out.println(sortTemp[i]);                           

    }                                                               

}

1.7主页面完成

package com.qfedu.student.system.mainproject;

import java.util.Scanner;

import com.qfedu.student.system.entity.Student;

import com.qfedu.student.system.manager.StudentManager;

public class MainProject {

    public static void main(String[] args) {

        StudentManager stm = new StudentManager();

        for (int i = 0; i < 15; i++) {

            Student student = new Student();

            student.setId(i + 1);

            student.setName("测试" + i);

           student.setGender(Math.random() > 0.5 ? '男' : '女');

            // 随机数

            student.setAge((int) (Math.random() * 100));

            student.setScore((int) (Math.random() * 100));

            stm.add(student);

        }

        Scanner sc = new Scanner(System.in);

        int choose = 0;

        int id = 0;

        while (choose != 7) {

            System.out.println("1. 添加新学生");

            System.out.println("2. 删除指定ID的学生");

            System.out.println("3. 修改指定ID的学生");

            System.out.println("4. 查询指定ID的学生");

            System.out.println("5. 查询所有学生");

            System.out.println("6. 按照成绩降序排序");

            System.out.println("7. 退出");

            choose = sc.nextInt();

            sc.nextLine();

            switch (choose) {

            case 1:

                /*

                * 大家自己完成提供给用户一些输入提示,完成添加操作

                */

                stm.add(new Student(100, "骚磊", 16, '男', 119));

                break;

            case 2:

                System.out.println("请输入需要删除学生的ID号");

                id = sc.nextInt();

                stm.remove(id);

                break;

            case 3:

                System.out.println("请输入需要修改信息的学生ID号");

                id = sc.nextInt();

                stm.modify(id);

                break;

            case 4:

                System.out.println("请输入需要查询信息的学生ID号");

                id = sc.nextInt();

                Student student = stm.get(id);

                if (null == student) {

                    System.out.println("查无此人");

                } else {

                    System.out.println(student);

                }

                break;

            case 5:

                stm.showAllStudents();

                break;

            case 6:

                stm.scoreSortDesc();

                break;

            case 7:

                System.out.println("程序退出...");

                break;

            default:

                System.out.println("选择错误");

                break;

            }

        }

    }

}

1.8项目后期功能

1. 数据持久化保存

    IO操作文件内容 String字符串解析

2. Sout界面分离

    除了viewer层,其他任何代码中不能出现任何一个Sout

3. 排序算法优化

    可以让排序方法能够根据用户指定条件进行排序操作

4. 自定义异常添加

    优化代码中错误提示和处理过程

5. 数据根据条件过滤展示

    根据用户指定条件,过滤展示对应的数据

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353