JAVA PTA随笔-21207220-万美玲

一、前言

 

这三次作业的题目集主要涉及到了Java基础知识,如控制台输入输出、字符串基本语法知识、控制语句、数组、类和对象、继承、封装性、日期类等。

其中,第一次作业的题目较为简单,主要是一些基本输入输出、计算处理、单位换算和字符串的简单处理。第二次作业的难度有所增加,需要掌握数组、封装性和面向对象编程等知识,也需要一些逻辑思考能力。第三次作业则更加注重面向对象编程和主要逻辑的实现,并且能够实现一些简单系统的初步实现,例如封装性、日期类和成绩统计等。总体来说,这三次作业是一个难度循序渐进的过程,对于Java基础能力的提升有很大的帮助,同时也能增强编程能力和问题解决能力。

题量上,三次作业分配比较平均,第一次作业题目数量多但每个题目都很精简,第三次题量减少而难度上升,代码量也能看到明显增加。很遗憾的第三次作业的课程成绩统计程序并没有达到要求正常运行,这说明我的编程能力还有很大不足,后续要查阅资料,不断学习,不断弥补不足。

 

JAVA是我初次学习面向对象的语言,这中编程思想于我而言是全新且陌生的,类的封装、属性和方法的定义,学习类的声明、定义与c语言有所异同,因此我也查询了关于两者的区别,让我更好理解JAVA语言的思想:

 

1语言类型:C语言是一种过程式编程语言,而Java是一种面向对象的编程语言。

 

2内存管理:在C语言中,需要手动管理内存分配和释放,包括使用malloc()free()等函数。而Java使用垃圾回收机制(Garbage Collection),自动管理内存的分配和释放,减少了程序员对内存管理的负担。

 

3平台独立性:C语言的代码是与特定的硬件平台相关的,因此需要针对不同平台进行编译。而Java通过Java虚拟机(JVM)来实现平台的独立性,只需要编写一次代码,就可以在不同的平台上运行。

 

4异常处理:Java提供了强大的异常处理机制,可以捕获和处理异常,保证程序的稳定性和可靠性。而C语言的错误处理主要依赖于返回值,需要程序员自行判断和处理。

 

5标准库:C语言的标准库相对较小,需要通过外部库来实现各种功能。而Java提供了丰富的标准库,包括网络、IO、数据库等功能,方便程序开发。

 

6多线程支持:Java天生支持多线程编程,提供了多线程相关的API,方便程序实现并发和多任务处理。而C语言需要使用操作系统提供的线程库来实现多线程编程。

 

设计与分析

(一)作业知识点和易错点分析

第一次作业:

7-1 身体质量指数(BMI)测算:主要考察了基本的输入输出和算术运算符的使用,注意测试边界值

7-2 长度质量计量单位换算:主要学习了基本的输入输出和算术运算符的使用,需要注意单位之间的转换关系。

7-3 NCHU_奇数求和:主要学习了循环语句的使用,需要注意判断语句的使用和求和的累加方式。

7-4 NCHU房产税费计算:主要学习了条件语句(if语句)和算术运算符的使用,需要注意不同条件下的税费计算方式。

7-5 游戏角色选择:主要学习了条件语句(if语句)和逻辑运算符的使用,需要根据不同的角色选择给出对应的提示。

7-6 NCHU学号识别:主要学习了字符串的基本操作,需要注意字符串的截取和比较方式。

7-7 NCHU_巴比伦法求平方根近似值:主要学习了循环语句和算术运算符的使用,需要注意平方根近似值的计算方式。

7-8 二进制数值提取:主要考察了位运算符和逻辑运算符的使用,需要注意二进制数值的提取方式。

7-8 判断三角形类型:主要学习判断条件处理包含关系,要注意边界值和异常值的处理。

 

第二次作业:

7-1 成绩计算-1-类、数组的基本运用:主要考察了类和数组的基本操作,需要注意成绩统计的计算方式和数组下标的使用。

7-2 成绩计算-2-关联类:主要考察了类的封装性和关联性,需要注意不同类之间的数据传递和处理方式。

7-3 有重复的数据:主要考察了数组和字符串的操作,需要注意去重算法的设计和实现方式。

7-4 去掉重复的数据:主要考察了集合类的操作,需要注意集合类去重的基本方法和使用方式。

7-5 面向对象编程(封装性):主要考察了类的封装性和面向对象编程思想,需要注意属性和方法的设计以及访问权限的设置等。

7-6 GPS测绘中度分秒转换:主要考察了数据类型和字符串操作,需要注意GPS坐标的表示方式以及度分秒与小数之间的转换方式。

7-7 菜单计价程序-1:主要考察了条件语句和循环语句的使用,需要注意菜单选择和价格计算的实现方式。

7-8 jmu-java-日期类的基本使用:主要考察了日期类的基本操作和格式化输出方法,需要注意日期格式的设置和转换方式。

 

第三次作业:

7-1 jmu-java-日期类的基本使用:主要考察了日期类的高级操作和异常处理,需要注意日期加减、比较和格式化输出的实现方式以及异常情况的处理。

7-2 课程成绩统计程序-1:主要考察了面向对象编程和封装性,需要注意类的设计和属性的设置,以及不同对象之间的数据传递和处理方式。

7-3 面向对象编程(封装性):同第二次作业的7-5题目,重点考察了类的封装性和面向对象编程思想。

7-4 判断两个日期的先后,计算间隔天数、周数:主要考察了日期类的高级操作,需要注意日期的比较和计算方式,以及对应的时间间隔单位的转换方式

(二)基本知识储备

1、循环嵌套,三角形的判断要注意包含关系和先后循序。例如等边直角三角形是特殊的直角三角形,等边三角形就是特殊的等腰三角形。当正常顺向逻辑过于复杂时,可以尝试逆向逻辑判断,例如可以利用补集的思想简化判断语句。

 

2正则表达式,利用菜鸟工具学习和测试正则表达式的正确性。

 

 

3、控制台输入输出的应用,控制台输入一般指键盘和鼠标,输出一般指显示屏。第一题有scanner对象的应用,输入身高体重,输出通过计算和if判断语句输出预期结果。

 

方法

描述

方法

描述

nextByte()

读取一个byte类型的整数

nextLong()

读取一个1ong

nextShort)

读取一个short类型的整数

nextFloat()

读取一个float

nextInt(

读取一个int类型的整数

nextDouble()

读取一个double

 

4、数值数据类型的相互转换,特别注意在当除法的两个操作数均为整数时,除法的结果为商,而小数部分被截去。例如,5/2的结果是2而不是2.5,面-5/2的结果是-2而不是-2.5。为了执行浮点数的除法,其中一个操作数必须是浮点数。例如,5.0/2的结果是2.5
操作符%称为取模操作符,在执行除法后得到余数。左边的操作数是被除数,右边的操数是除数。奇数求和问题中的判断语句中就使用到了,如下:

if(num%2==1||num%2==-1)

操作符%通常用于正整数,但也可用于负整数和浮点值。只有当被除数是负数时,余数才是负的。例如,-7%3的结果是-1,-12%4的结果是0,-26%-8的结果是-2,20%-13的结果是7

在长度质量计算单位换算时,如下:

System.out.printf((float)quality+" "+(float)length);

就用到了强制类型转换,将数值类型强制转换为float类型。

 

表  数值数据类型

 

类型名

范围

存储空间

byte

-2~27-1(-128~127)

8位带符号数

short

-215~215-1(-32768 ~32767)

16位带符号数

32位带符号数

int

-2³1~2³1-1(-2 147483648 ~2147483 647)

1ong

-26³~26³-1

(-9223 372 036854775808~9223372 036854775 807)

64位带符号数

float

负数范围:-3.4028235E+38~-1.4E-45

正数范围:1.4E-45~3.4028235E+38

32,标准IEEE7

double

负数范围:-1.7976931348623157E+308~-4.9E-324

正数范围:4.9E-324~1.7976931348623157E+308

64,标准IEEE7

 

 

5、异常值和边界值的测试

正确的输入输出格式,输入注意空格,输出注意首尾空格的保留和去除,可以使用

1.String.trim()去掉首尾空格

2.str.replace(" ",""); 去掉所有空格,包括首尾、中间
3.或者replaceAll("+","")去掉所有空格

4.str =.replaceAll("\s*", "");可以替换大部分空白字符, 不限于空格可以匹配空格、制表符、换页符等空白字符的其中任意一个

(三)部分源码分析

7-1成绩计算-1-类、数组的基本运用

 1 import java.math.BigDecimal;
 2 import java.util.Scanner;
 3 class Student
 4 {
 5         String number;
 6         String name;
 7         int chinese;
 8         int math;
 9         int physics;
10 
11     public Student(String number,String name,int chinese,int math,int physics){
12         this.number=number;
13         this.name=name;
14         this.chinese=chinese;
15         this.math=math;
16         this.physics=physics;
17     }
18     
19     public int totalcoin(){
20         return chinese+math+physics;
21     }
22 
23     public double averagecoin(){
24         BigDecimal average=BigDecimal.valueOf(totalcoin()).divide(BigDecimal.valueOf(3),2,BigDecimal.ROUND_HALF_UP);
25         return average.doubleValue();
26     }
27 }
28 
29 
30 public class Main{
31     public static void main(String[] args)
32     {
33         Scanner input=new Scanner(System.in);
34         for(int i=0;i<5;i++)
35         {
36             String getinput=input.nextLine();
37             String[] stu=getinput.split(" ");
38 
39             String number=stu[0];
40             String name=stu[1];
41             int chinese=Integer.parseInt(stu[2]);
42             int math=Integer.parseInt(stu[3]);
43             int physics=Integer.parseInt(stu[4]);
44             Student student=new Student(number,name,chinese,math,physics);
45             int totalscore=student.totalcoin();
46             double averagescore=student.averagecoin();
47             System.out.println(number+" "+name+" "+totalscore+" "+String.format("%.2f",averagescore));
48         }
49     }
50 
51 }

在程序中,定义了一个 Student 类,表示学生对象,其中包括学号、姓名、语文、数学、物理成绩。类中定义了一些方法,如 totalcoin() 方法用于计算总分数,averagecoin() 方法用于计算平均分数等。

程序的入口是 main 方法,通过 Scanner 类读取用户输入,使用 split 方法将输入字符串按空格分隔成数组,提取出学号、姓名、语文、数学和物理成绩,并传入 Student 类的构造函数创建学生对象。

然后调用 Student 类中的方法计算总分数和平均分数,并使用 System.out.println() 方法将结果输出到控制台。

该程序中使用了 BigDecimal 类对浮点数进行处理,避免了浮点数在计算中产生的精度问题。同时,在输出平均分数时使用了 String.format() 方法格式化输出结果,保留两位小数。

 

7-2 成绩计算-2-关联类

 

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.math.BigDecimal;

class Score {
    private int dailyGrade;
    private int finalGrade;

    public Score(int dailyGrade, int finalGrade) {
        this.dailyGrade = dailyGrade;
        this.finalGrade = finalGrade;
    }

    public double calculateDailyAverage() {
        return dailyGrade;
    }

    public double calculateFinalAverage() {
        return finalGrade;
    }

    public int calculateSum() {
        return (int) (dailyGrade * 0.4 + finalGrade * 0.6);
    }
}

class Student {
    private String number;
    private String name;
    private Score chinese;
    private Score math;
    private Score physics;
    private Map<String, Score> scores;
    

    public Student(String number, String name) {
        this.number = number;
        this.name = name;
        this.scores = new HashMap<>();
    }

    public void addScore(String courseId, Score score) {
        scores.put(courseId, score);
    }

    public double calculateDailyAverage() {
        double totalDailyGrade = 0;
        int count = 0;
        for (Score score : scores.values()) {
            totalDailyGrade += score.calculateDailyAverage();
            count++;
        }
        return totalDailyGrade / count;
    }

    public double calculateTotalAverage() {
        double totalAverage = 0;
        int count = 0;
        for (Score score : scores.values()) {
            totalAverage += score.calculateSum();
            count++;
        }
        return totalAverage / count;
    }

    public double calculateFinalAverage() {
        double totalFinalGrade = 0;
        int count = 0;
        for (Score score : scores.values()) {
            totalFinalGrade += score.calculateFinalAverage();
            count++;
        }
        return totalFinalGrade / count;
    }

    public int calculateTotalScore() {
        int totalScore = 0;
        for (Score score : scores.values()) {
            totalScore += score.calculateSum();
        }
        return totalScore;
    }

    public String getNumber() {
        return number;
    }

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        Map<String, Student> students = new HashMap<>();

        while (input.hasNextLine()) {
            String getInput = input.nextLine();
            String[] stu = getInput.split(" ");

            String number = stu[0];
            String name = stu[1];
            String courseId = stu[2];
            int dailyGrade = Integer.parseInt(stu[3]);
            int finalGrade = Integer.parseInt(stu[4]);

            Student student = students.getOrDefault(number, new Student(number, name));
            student.addScore(courseId, new Score(dailyGrade, finalGrade));
            students.put(number, student);
        }

        for (Student student : students.values()) {
            double dailyAverage = student.calculateDailyAverage();
            double totalAverage = student.calculateTotalAverage();
            double finalAverage = student.calculateFinalAverage();
            int totalScore = student.calculateTotalScore();
            System.out.printf("%s %s %d %.2f %.2f %.2f%n", student.getNumber(), student.getName(), totalScore, dailyAverage, finalAverage, totalAverage);
        }
    }
}

 

 

定义了一个 Score 类,表示学生的一门课程成绩,包括平时成绩和期末成绩。类中定义了一些方法,如 calculateSum() 方法用于计算总分数,calculateAverage() 方法用于计算平均分数等。

定义了一个 Student 类,表示学生对象,包括学号、姓名以及多门课程的成绩。类中定义了一些方法,如 addScore() 方法用于添加学生的课程成绩,calculateDailyAverage() 方法用于计算每门课程的日常成绩的平均分数,calculateTotalAverage() 方法用于计算每门课程的总成绩的平均分数,calculateFinalAverage() 方法用于计算每门课程的期末成绩的平均分数,calculateTotalScore() 方法用于计算每门课程的总分数等。

main 方法中,使用 Scanner 类读取用户输入。循环读取每行输入,将输入按空格分隔成数组,提取出学号、姓名、课程ID、日常成绩和期末成绩。然后判断该学生是否已存在,若存在则获取该学生对象,若不存在则创建新的学生对象。再将当前课程成绩添加到该学生对象的成绩列表中。最后将该学生对象存入一个 Map 中,以学号作为键。

遍历 Map 中的学生对象,分别计算每门课程的平时平均分数、总成绩平均分数和期末平均分数,并计算每门课程的总分数。使用 System.out.printf() 方法格式化输出结果。

7-7 菜单计价程序-1

 

import java.util.Scanner;
class Dish
{
    String name;
    int unit_price;

    public void setname(String name)
    {
        this.name=name;
    }
    public String getname()
    {
        return name;
    }
    
    public void setunit_price(int unit_price)
    {
        this.unit_price=unit_price;
    }
    public int setunit_price()
    {
        return unit_price;
    }
    int getPrice(int portion)
    {
        if(portion==1)
            return unit_price;
        else if(portion==2)
            return (int)Math.round(unit_price*1.5);
        else if(portion==3)
            return unit_price*2;
        else
            return -1;
    }

}
class Menu
{
     Dish[] dishs;
     public Dish searthDish(String dishName)
    {
        for (Dish dish: dishs)
        {
        if (dish.name.equals(dishName))
            return dish;
        }
       return null;
    }
}
class Record 
{
    Dish dish;
    int portion;
    int getPrice()
    {
        return dish.getPrice(portion);
    }
}
class Order
{
    Record[] records;
    int getTotalPrice()
    {
        int totalPrice = 0;
        for (Record record : records)
        {
            totalPrice += record.getPrice();
        }
        return totalPrice;
    }
    Record addARecord(String dishName, int portion)
    {
        Record record = new Record();
        Menu menu = new Menu();
        Dish dish = menu.searthDish(dishName);
        if (dish == null)
        {
            System.out.println(dishName + " does not exist");
            return null;
        }
        record.dish = dish;
        record.portion = portion;
        return record;
    }
}
public class Main
{
    public static void main(String[] args)
    {
        Scanner input=new Scanner(System.in);
        String dish;
        String []menu1 =new String[]{"清炒土豆丝","西红柿炒蛋","油淋生菜","麻婆豆腐"};
        int []price1=new int[]{12,15,9,12};
        int sumprice=0;
        int size1;
        for(;;)
        {
            int flag=0;
            dish=input.next();
            if(dish.equals("end"))
                break;
            size1=input.nextInt();
            for(int i=0;i<4;i++)
            {
                if(dish.equals(menu1[i]))
                {
                  flag=1;
                  int basicprice=price1[i];
                  if(size1==1)sumprice=sumprice+basicprice;
                  if(size1==2)sumprice=sumprice+(int)Math.round(basicprice*1.5);
                  if(size1==3)sumprice=sumprice+basicprice*2;
                }
            }
            if(flag==0)System.out.println(dish+" does"+" "+"not"+" "+"exist");
        }
        System.out.println(sumprice);
    }
}

定义了一个 Dish 类,表示菜品,包括菜名和单价。类中定义了一些方法,如 setname() 方法用于设置菜名,getname() 方法用于获取菜名,setunit_price() 方法用于设置单价,getunit_price() 方法用于获取单价,getPrice() 方法用于根据份数计算价格。

定义了一个 Menu 类,表示菜单,包括多个菜品。类中定义了一个菜品数组 dishs,并且有一个 searthDish() 方法用于根据菜名查找菜品,返回匹配的菜品对象。

定义了一个 Record 类,表示记录,包括菜品和份数。类中定义了一个 getPrice() 方法,调用菜品的 getPrice() 方法计算总价。

定义了一个 Order 类,表示订单,包括多个记录。类中定义了一个记录数组 records,并且有一个 getTotalPrice() 方法用于计算订单的总价,以及一个 addARecord() 方法用于添加一条记录到订单中。

main 方法中,使用 Scanner 类读取用户输入。首先定义一个菜单数组 menu1 和一个价格数组 price1,分别存储菜名和对应的价格。然后进入一个无限循环,读取用户输入的菜名和份数。通过遍历菜单数组,判断菜名是否存在于菜单中,如果存在则根据份数计算价格,并累加到 sumprice 中;如果不存在,则输出错误提示信息。循环直到用户输入 "end" 结束点餐。最后输出 sumprice 表示订单的总价。

 

7-3测试题由于本人编译并未通过,所以不予罗列。

 

三、踩坑心得

 

在第一次作业中,因为不了解控制台输入输出规则,输出格式不正确导致测试点一直过不了。在成绩计算作业中,使用了 BigDecimal 类对浮点数进行处理,避免了浮点数在计算中产生的精度问题,用String.format()格式化输出格式。

 

使用数据时,忘记进行数据类型转换,例如在学号识别题目中,对字符串进行处理时把字符串类型当作数值类型进行处理,导致编译不通过。如:System.out.printf((float)quality+" "+(float)length);中,开始没有强制转换为float类型,导致测试点无法通过。

 

  程序中没有进行数据校验和错误处理,有时会导致程序崩溃或输出错误结果。例如我的很多程序中都没有输入终止代码,scanf输入入口未关闭。

 

  在写代码的过程中,没有进行适当注释,导致自己要花费大量时间去回想前面写过代码的功能,导致编码效率不高。

 

判断闰年要注意闰年和平年二月份的区别,日期的计算过程中要注意判断边界值,例如1231日的下一天是11日,月份变为1月年份也要加一。

 

四、主要困难及改进建议

 

第三次作业课程统计程序未能实现,对类的封装、联系和继承关系还有很多知识盲区,有很大进步空间。

 

在学习日期类时,当时未完全了解日期的几种更新迭代,导致后期写的代码格式混乱,混杂了几种日期类。

 

学习过程中,感觉学习资料不够全面,在课本和网络上查找的都不够全面,导致代码一直处于修改的状态。

在日后的学习过程中,写代码前先罗列各个类之间的联系,并且尽量减少其联系,做到条理清晰,类间各司其职以改进代码效率。

 

 

 

五、总结

 

总体来说,这三次作业是一个难度循序渐进的过程,对于Java基础能力的提升有很大的帮助,同时也能增强编程能力和问题解决能力。通过这三次PTA的练习。我也明白了在语言类的学习中要注重实践,多编码才能找到问题所在,编码练习也是快速提高编程能力的方法。

 

另外,我也明白了自己还存在很多不足,并且能发现这些不足,并在以后的学习中找到方向,弥补这些不足。对于类的封装和继承关系、日期类的使用、边界值的测试要更加用心。

 

posted @ 2023-10-07 23:16  半生微微醺  阅读(52)  评论(0)    收藏  举报