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*", "");可以替换大部分空白字符, 不限于空格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输入入口未关闭。
在写代码的过程中,没有进行适当注释,导致自己要花费大量时间去回想前面写过代码的功能,导致编码效率不高。
判断闰年要注意闰年和平年二月份的区别,日期的计算过程中要注意判断边界值,例如12月31日的下一天是1月1日,月份变为1月年份也要加一。
四、主要困难及改进建议
第三次作业课程统计程序未能实现,对类的封装、联系和继承关系还有很多知识盲区,有很大进步空间。
在学习日期类时,当时未完全了解日期的几种更新迭代,导致后期写的代码格式混乱,混杂了几种日期类。
学习过程中,感觉学习资料不够全面,在课本和网络上查找的都不够全面,导致代码一直处于修改的状态。
在日后的学习过程中,写代码前先罗列各个类之间的联系,并且尽量减少其联系,做到条理清晰,类间各司其职以改进代码效率。
五、总结
总体来说,这三次作业是一个难度循序渐进的过程,对于Java基础能力的提升有很大的帮助,同时也能增强编程能力和问题解决能力。通过这三次PTA的练习。我也明白了在语言类的学习中要注重实践,多编码才能找到问题所在,编码练习也是快速提高编程能力的方法。
另外,我也明白了自己还存在很多不足,并且能发现这些不足,并在以后的学习中找到方向,弥补这些不足。对于类的封装和继承关系、日期类的使用、边界值的测试要更加用心。
浙公网安备 33010602011771号