题目集1-3的总结Blog

一、前言

在近来的三次实验中,学习到的知识自然不容多疑,但同样的,遇到的困难也一点点的呈现了。

知识点包括如下:

1、创建类,在四个题目中,里面最多使用的就是我们最近强调的使用类,类对象封装数据。

2、类型定义:类和对象、属性和方法等的定义。

题量比较大的,对于初学的我们而言要一个个去研究的话也是需要大量的时间的。难度与我而言存在一定的难度,基础的基本没问题了,但是对于进一步的内容掌握并不太稳定,相对于刚开始接触到新内容的我来说是有一定的困难。

二、设计与分析

7-1

创建学生类,包含

属性:学号(String)、姓名(String)、语文成绩(int)、数学成绩(int)、物理成绩(int)

方法:计算总分、计算平均分

输入5个学生的信息,将每个学生的信息封装在一个学生对象中。

按输入顺序依次输出5个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。

 

import java.util.Scanner;
class Student {
    private String stuId;
    private String name;
    private int chinese;
    private int math;
    private int physics;
    public Student(String stuId, String name, int chinese, int math, int physics) {
        this.stuId = stuId;
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.physics = physics;
    }
    public int getTotalScore() {
        return chinese + math + physics;
    }
    // 计算平均分
    public double getAverageScore() {
        return getTotalScore() / 3.0;
    }
    // 获取学生信息
    public String getStudentInfo() {
        return stuId + " " + name;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Student[] stu = new Student[5];
        //记录学生信息
        for (int i = 0; i < 5; i++) {
            String line = scanner.nextLine();
            String[] info = line.split(" ");
            String studentId = info[0];
            String name = info[1];
            int chinese = Integer.parseInt(info[2]);
            int math = Integer.parseInt(info[3]);
            int physics = Integer.parseInt(info[4]);
            stu[i] = new Student(studentId, name, chinese, math, physics);
        }
        //分析过后的学生成绩信息
        for (int i = 0; i < 5; i++) {
            Student student = stu[i];
            //get学生信息,输出总分和三科的平均分
            String output = student.getStudentInfo() + " " + student.getTotalScore() + " " + String.format("%.2f", student.getAverageScore());
            System.out.println(output);
        }
        scanner.close();
    }
}

7-1类图如下:

 7-1复杂度如下:

 

 

 这是在7-1的第一次提交上的内容,输出样例错误

 上述为学生信息的输入函数,在源代码内因为没有对输入的学生信息进行录入和处理,空有一个输入在,所以导致后面的错误产生

改进:

 加入代码:stu[i] = new Student(studentId, name, chinese, math, physics); 在Main内部声明。

 

7-2

 

创建成绩类,包含:

属性:平时成绩(int)、期末成绩(int)

方法:计算总成绩(计算规则:平时成绩*0.4+期末成绩*0.6,保留整数部分,小数部分直接丢弃)

创建学生类,包含:

属性:学号(String)、姓名(String)、语文成绩(成绩类)、数学成绩(成绩类)、物理成绩(成绩类)

方法:计算总分、计算平均分

输入3个学生的信息,将每个学生的信息封装在一个学生对象中。

按输入顺序依次输出3个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。

 7-2的类图如下:

 7-2的复杂度如下:

 

 

 

第一次没有添加对成绩的处理,添加俩个对平时成绩和期末成绩的处理函数

 之后答案成为了

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int i, j;
        int arrayLength = 3;
        Student[] stu = new Student[arrayLength];
        Score[][] scores = new Score[arrayLength][arrayLength];
        for (i = 0; i < arrayLength; i++){
            stu[i] = new Student();
        }
        for (i = 0; i < arrayLength; i++){
            for (j = 0; j < arrayLength; j++){
                scores[i][j] = new Score();
            }
        }
        double a = 0, b = 0, c = 0;
        int[] n1 = new int[arrayLength];
        int[] n2 = new int[arrayLength];
        int[] n3 = new int[arrayLength];
        for (i = 0; i < arrayLength; i++){
            for (j = 0; j < arrayLength; j++){
                stu[i].ID = input.next();
                stu[i].name = input.next();
                String lesson = input.next();
                scores[i][j].regularscore = input.nextInt();
                scores[i][j].finalscore = input.nextInt();
                a += scores[i][j].finalscore();
                b += scores[i][j].regularscore;
                c += scores[i][j].finalscore;
            }
            n1[i] = (int) a;//总分
            n2[i] = (int) b;//平时分
            n3[i] = (int) c;//期末分
            a = 0;
            b= 0;
            c = 0;
        }
        for (i = 0; i < arrayLength; i++){
            System.out.printf("%s %s %d %.2f %.2f %.2f\n", stu[i].getID(), stu[i].getName(), n1[i], n2[i] / 3.0, n3[i] / 3.0, n1[i] / 3.0);
        }
    }



    public static class Score{
        private int regularscore;
        private int finalscore;
        public int finalscore(){
            return (int) (regularscore * 0.4 + finalscore * 0.6);
        }
        public Score(int regularscore, int finalscore){
            this.finalscore = finalscore;
            this.regularscore = regularscore;
        }
        public Score(){
            this(0, 0);//初始化平时成绩和期末成绩
        }
    }
    public static class Student{
        private String ID;
        private String name;
        private int chinese;
        private int math;
        private int physics;
        public Student(String ID, String name, int chinese, int math, int physics){
            this.ID = ID;
            this.name = name;
            this.chinese = chinese;
            this.math = math;
            this.physics = physics;
        }
        public Student(){
            this("", "", 0, 0, 0);//学生信息
        }
        public String getID(){
            return ID;
        }
        public String getName(){
            return name;
        }
        public int getChinese(){
            return chinese;
        }
        public int getMath(){
            return math;
        }
        public int getPhysics(){
            return physics;
        }
        public int getTotal(){
            return chinese + math + physics;
        }
        public double getAverage(){
            return getTotal() / 3.0;
        }
    }
}

 另外的不清楚问题出现在哪里,不理解“课程顺序不一致”的问题出现在哪里。

 

 7-7

某饭店提供4种菜,每种菜品的基础价格如下:
西红柿炒蛋 15
清炒土豆丝 12
麻婆豆腐 12
油淋生菜 9
设计点菜计价程序,根据输入的订单,计算并输出总价格。
订单由一条或多条点菜记录组成,每条记录一行,最后以"end"结束
每条点菜记录包含:菜名、份额两个信息。
份额可选项包括:1、2、3,分别代表小、中、大份)
不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格
2。

如果计算出现小数,按四舍五入的规则进行处理。
参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
}
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
}
点菜记录类:保存订单上的一道菜品记录
Record {
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格
}
订单类:保存用户点的所有菜的信息。
Order {
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(String dishName,int portion)
//添加一条菜品信息到订单中。
}

7-7类图如下:

 

7-7图复杂度如下:

 

 经过前面来个类的运用,在这一题的使用上,就凸现的会比较简单一点,在本题里面,多数用到的是字符的对比以及字符的输出,判断字符等。

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String []menu =new String[]{"西红柿炒蛋","清炒土豆丝","麻婆豆腐","油淋生菜"};
        String dish;
        int size;
        int totalPrice = 0;
        double price = 0;
        int judge = 0;
        while(true){
            dish = input.next();
            if(dish.equals( "end" )){
                break;
            }
            size = input.nextInt();
            if(size == 1) price = 1;
            if(size == 2) price = 1.5;
            if(size == 3) price = 2;
            if(dish.equals(menu[0])){
                judge = 0;
            }else if(dish.equals(menu[1])){
                judge = 1;
            }else if(dish.equals(menu[2])){
                judge = 2;
            }else if(dish.equals(menu[3])){
                judge = 3;
            }else{
                System.out.println(dish + " does not exist");
                continue;
            }
            switch(judge){
                case 0:
                    totalPrice += Math.round(15 * price);//Math.round计算价格
                    break;
                case 1:
                    totalPrice += Math.round(12 * price);
                    break;
                case 2:
                    totalPrice += Math.round(12 * price);
                    break;
                case 3:
                    totalPrice += Math.round(9 * price);
                    break;
                default:
                    System.out.println(input + " does not exist");
                    break;
            }
        }
        System.out.println(totalPrice);
    }
}

 

 

 T3 7-2

某高校课程从性质上分为:必修课、选修课,从考核方式上分为:考试、考察。

考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。

考察的总成绩直接等于期末成绩

必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。

 第三题的参考类图如上,在这个题目上由于限制条件的约束,我没能写出来,但是大概的基本条件需要我是了解的,以及需要用到的知识点。

 本人能力有限,代码能力有待提高。

 

三、踩坑心得

7-1:

类的封装性:Student类使用了private访问修饰符来限制stuId、name、chinese、math、physics属性的直接访问,通过提供公共的构造方法和方法来进行操作和获取属性的值。这样做可以保证数据的安全性和一致性。
主函数main():在主函数中,通过Scanner类从标准输入读取学生的信息,并根据空格分割成学号、姓名、语文成绩、数学成绩和物理成绩。然后通过实例化Student对象来存储每个学生的信息,并将所有学生的成绩依次输出。

7-2:

封装Score和Student类来存储每个学生的成绩和信息,并计算出每个学生的总分和平均分。
finalscore()方法:该方法用于计算最终成绩,通过将regularscore(平时成绩)和finalscore(期末成绩)按照一定比例相加来得到最终成绩。需要注意的是,在计算过程中,没有进行类型转换,因此返回值为double类型。getID()和getName()方法:这两个方法分别用于获取学生的学号和姓名。这里直接返回了Student类中定义的ID和name属性的值。
getTotal()和getAverage()方法:这两个方法分别用于计算学生的总分和平均分。需要注意的是,在计算平均分时,通过除以3.0来避免整数除法的舍入误差。
需要注意的是,在计算每个学生的总分、平均分和各科成绩时,需要定义相应的变量(如a、b、c、n1、n2、n3等),并进行正确的类型转换。此外,该程序假设只有三门科目,如果需要处理更多科目的成绩,需要相应地调整数组的大小。

 7-7:

对菜名的大小写敏感问题:一般来说,应该将用户输入的菜名和菜单中的菜名全部转换为小写或大写字母,以避免用户输入大小写不匹配导致的错误。例如可以使用 dish.toLowerCase()menu[i].toLowerCase() 进行大小写转换。
输入菜品大小的合法性检查问题:当用户输入菜品大小时,需要进行合法性检查,并在输入不合法时给出提示信息。例如可以添加范围判断语句,并输出提示信息 System.out.println("Invalid size: " + size)
数组越界问题:在判断输入的菜名是否存在菜单中时,需要考虑输入的菜名是否超过了菜单数组的长度,否则会导致数组越界。应该通过循环和判断来遍历菜单数组。计算菜品价格时数据类型的选择问题:
在计算总价时,可以使用整型或浮点数类型(如 int 和 double),但是需要根据实际需求选择合适的数据类型,并进行类型转换。例如可以使用 totalPrice += (int) Math.round(price * priceList[judge]);
对计算结果进行转换。输出错误信息的问题:当输入的菜名不存在时,应该输出提示信息,并提示用户重新输入。例如可以使用 System.out.println(dish + " does not exist, please input again."); 进行提示。
程序退出逻辑的问题:当前代码中使用 break 语句来退出程序,但是在实际应用中,可能存在多个循环嵌套的情况,这时候采用 break 语句容易造成程序失控。建议改为使用 return 语句来退出当前方法,或者使用布尔类型变量来控制循环的退出条件。

四、主要困难以及改进意见

 

对类的定义和调用不熟练是很常见的问题,需要在实践中不断积累经验。在7-2和7-3中,我们可以通过定义一个专门处理正则表达式的类来避免大量重复的代码。这样能够提高代码的复用性和可维护性,减少出错的可能性,同时也使得代码更易于扩展和更新。
在将分割好的字符串转变为double类型的数时,确实也可以将这个部分的代码划分为一个单独的类。这个类可以封装字符串转换的过程,并在其他程序中重复使用。这样能够提高代码的可读性和可维护性,减少出错的可能性,同时也使得代码更易于应对各种需求变化。
总之,通过将相似或重复的代码划分到一个类中,可以提高代码的复用性、可读性、可维护性和可扩展性,减少出错的可能性。同时,这也符合面向对象编程的核心思想:封装、继承和多态。因此,我们在编写程序的时候,要善于分析出哪些代码可以划分到一个类中,以提高代码的品质和效率。
以下有有关的意见:
在课堂上讲解如何使用类来提高代码的复用性和可维护性,以及如何在程序中划分类;鼓励学生在编写程序时,积极思考如何将相似或重复的代码划分到一个类中,并在评分中给予额外加分;

五、总结

 

1、通过这四次的pta作业,我对Java有了很大的提升,并深刻认识到了面向对象编程的好处和重要性。在编写算法之前,我意识到了将要实现的功能细分为多个类,并清晰地定义每个类的功能任务的重要性。这样做不仅可以提高代码编写的效率,还能增强代码的可复用性,并提升自己的思维逻辑能力。

2、我对正则表达式有了更深入的理解,并体会到了在处理规定格式的数据时,正则表达式的实用性。它能够快速而灵活地匹配和提取需要的信息,为文本处理提供了便利。另外,正则表达式在处理规定格式的文本时具有很强的实用性,能够快速有效地匹配和提取需要的信息。

3、7-7的代码逻辑相对简单,但存在一些需要改进的地方。需要改进的地方包括:异常处理不完善、硬编码的菜品大小判断、浮点数计算可能导致的精度问题、缺乏友好的菜品不存在提示、缺乏模块化和面向对象的设计。

通过改进这些问题,能够提升代码的稳定性、可读性和可维护性。

我建议老师在课堂上讲解一些难题的解题思路,以及一些平时不常涉及的测试点。这样的授课方式可以帮助我们节省时间,在遇到难以察觉或少见的测试点时能够更快地找到解决方案。毕竟,对于我们提升编程能力来说,过于隐蔽或不常见的测试点并没有太大的帮助。另外就是自己对于自己的期望会过于大,以至于最后都无法达到作业的标准,也达不到自己预期想要的结果,成长的也微不足道。

 

posted @ 2023-10-07 20:08  x_xing  阅读(19)  评论(1)    收藏  举报