一.前言
(1)、第一次作业的题目量比较大,题目的难度低,仅有 7-7 判断三角形类型稍有难度。主要是让我们简单地熟悉java语言的编写过程。java语言的大部分语言使用和C语言相似,如选择、判断、循环等,但面向对象这一JAVA语言的特点和C语言面向过程的特点有着不小的差距。
面向对象编程和面向过程编程是两种主要的编程范式,它们在思维方式、代码组织方式、重用性和维护性等方面有明显的区别。
思维方式:面向过程编程是以过程为中心的,把解决问题的步骤分析出来,然后按顺序调用函数一步一步实现。而面向对象编程是将事物对象化,通过对象间的交互来解决问题。在面向对象编程中,数据和对数据的操作是绑定在一起的,即每个对象都有自己的属性和方法。
代码组织方式:面向过程编程的数据和对数据的操作是分离的,即数据和函数是独立的。而面向对象编程中,数据和对数据的操作是封装在一起的,即每个对象都有自己的状态和行为。这使得面向对象编程更易于理解和维护,因为对象的状态和行为是紧密相关的。
重用性:面向对象编程通过继承和多态等机制,可以更容易地实现代码的重用。子类可以继承父类的属性和方法,并可以根据需要对其进行扩展或修改。这使得面向对象编程更易于构建大型、复杂的系统。
维护性:由于面向对象编程中的代码是封装在对象中的,因此更易于维护和修改。当需要修改某个对象的行为时,只需要修改该对象的方法即可,而不会影响其他对象的行为。
但是在进行第一次作时我对这些概念知识一知半解,代码基本上还是在按照C语言的面向过程编写。
(2)、第二次作业相比第一次就开始有了明显的上升,开始正式地使用类(class),运用面向对象的方法开始编写代码。7-8 jmu-java-日期类的基本使用:给定一个日期,判定是否为合法日期。如果合法,判断该年是否闰年,该日期是当年第几天、当月第几天、当周第几天。给定起始日期与结束日期,判定日期是否合法且结束日期是否早于起始日期。如果均合法,输出结束日期与起始日期之间的相差的天数、月数、年数。这一题在第一次做的时候给我带来了很大的困难,导致这道题没能通过检测。
(3)、第三次作业的量不大,但是第二题的难度较高,实现功能的代码的所需的行数较前两次作业有了很大的提高,需要近400行代码才能实现要求。较长的编码给我带来了不小的困难,导致这次作业得分很低。另外的三道题则是在前两次作业的题目的基础上增加新需求,如果对前两次的题目有独立的思考,难度不是太大,部分题目需要用到课堂讲到的正则表达式。
二.设计与分析
题目一:第二次作业 7-1 成绩计算-1-类、数组的基本运用
题目:
创建学生类,包含:
属性:学号(String)、姓名(String)、语文成绩(int)、数学成绩(int)、物理成绩(int)
方法:计算总分、计算平均分
输入5个学生的信息,将每个学生的信息封装在一个学生对象中。
按输入顺序依次输出5个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。
源码分析:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Student[] students = new Student[5];
for (int i = 0; i < 5; i++) {
String studentID = scanner.next();
String name = scanner.next();
int Chinesescore = scanner.nextInt();
int mathScore = scanner.nextInt();
int physicsScore = scanner.nextInt();
students[i] = new Student(studentID, name, Chinesescore, mathScore, physicsScore);
}
for (Student student : students) {
System.out.printf("%s %s %d %.2f\n", student.getId(), student.getName(), student.getTotalScore(), student.getAverageScore());
}
}
}
class Student{
private String studentID;
private String name;
private int Chinesescore;
private int mathScore;
private int physicsScore;
public Student(String studentID, String name, int Chinesescore, int mathScore, int physicsScore) {
this.studentID = studentID;
this.name = name;
this.Chinesescore = Chinesescore;
this.mathScore = mathScore;
this.physicsScore = physicsScore;
}
public String getId() {
return studentID;
}
public String getName() {
return name;
}
public int getChinesescore() {
return Chinesescore;
}
public int getMathScore() {
return mathScore;
}
public int getPhysicsScore() {
return physicsScore;
}
public int getTotalScore() {
return Chinesescore + mathScore + physicsScore;
}
public double getAverageScore() {
return (Chinesescore + mathScore + physicsScore) / 3.0;
}
}
这个Java程序,它的主要功能是读取学生信息并计算学生的总分和平均分,然后打印出这些信息。
具体来说:
主要部分是main方法。在这个方法中,程序首先创建一个Scanner对象,用于从标准输入读取信息。然后,它创建一个Student数组,可以存储5个学生信息。
在第一个for循环中,程序通过Scanner对象从标准输入读取5个学生的信息,包括学生ID,姓名,语文分数,数学分数和物理分数。每读取到一个学生的信息,就使用这些信息创建一个新的Student对象,并将其添加到Student数组中。
在第二个for循环中,程序遍历Student数组,并为每个学生打印出他们的ID,姓名,总分和平均分。打印格式是"%s %s %d %.2f\n",其中第一个%s表示学生ID,第二个%s表示学生姓名,%d表示学生总分,%.2f表示平均分(保留两位小数)。
Student类定义了一个学生的基本属性和方法。每个学生的信息在类的构造函数中初始化,并提供了获取和计算学生总分和平均分的方法。
题目二:成绩计算-2-关联类
题目:
创建成绩类,包含:
属性:平时成绩(int)、期末成绩(int)
方法:计算总成绩(计算规则:平时成绩*0.4+期末成绩*0.6,保留整数部分,小数部分直接丢弃)
创建学生类,包含:
属性:学号(String)、姓名(String)、语文成绩(成绩类)、数学成绩(成绩类)、物理成绩(成绩类)
方法:计算总分、计算平均分
输入3个学生的信息,将每个学生的信息封装在一个学生对象中。
按输入顺序依次输出3个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。
代码分析:
import java.util.Scanner;
class Score {
int usually;
int finallyscore;
public Score(int usually, int finallyscore) {
this.usually = usually;
this.finallyscore = finallyscore;
}
}
class Student {
String id;
String name;
String prejict;
double score1;
double score2;
public Student(String id, String name, String prejict, double score1, double score2) {
this.id = id;
this.name = name;
this.prejict = prejict;
this.score1 = score1;
this.score2 = score2;
}
public int totalscore(){
return (int)(score1 * 0.4 + score2 * 0.6);
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Student[] students = new Student[9];
for(int i = 0; i<9; i++){
String id = scanner.next();
String name = scanner.next();
String prejict = scanner.next();
double score1 = scanner.nextDouble();
double score2 = scanner.nextDouble();
students[i] = new Student(id,name,prejict,score1,score2);
}
System.out.print(students[0].id+" "+students[1].name+" ");
System.out.print(students[0].totalscore() + students[1].totalscore() + students[2].totalscore()+" ");
System.out.print(String.format("%.2f",(students[0].score1+students[1].score1+students[2].score1)/3.00) +" " );
System.out.print(String.format("%.2f",(students[0].score2+students[1].score2+students[2].score2)/3.00)+" ");
System.out.println(String.format("%.2f",(students[0].totalscore() + students[1].totalscore() + students[2].totalscore())/3.00));
System.out.print(students[4].id+" "+students[4].name+" ");
System.out.print(students[3].totalscore() + students[4].totalscore() + students[5].totalscore()+" ");
System.out.print(String.format("%.2f",(students[3].score1+students[4].score1+students[5].score1)/3.00) +" " );
System.out.print(String.format("%.2f",(students[3].score2+students[4].score2+students[5].score2)/3.00)+" ");
System.out.println(String.format("%.2f",(students[3].totalscore() + students[4].totalscore() + students[5].totalscore())/3.00));
System.out.print(students[7].id+" "+students[7].name+" ");
System.out.print(students[6].totalscore() + students[7].totalscore() + students[8].totalscore()+" ");
System.out.print(String.format("%.2f",(students[6].score1+students[7].score1+students[8].score1)/3.00) +" " );
System.out.print(String.format("%.2f",(students[6].score2+students[7].score2+students[8].score2)/3.00)+" ");
System.out.println(String.format("%.2f",(students[6].totalscore() + students[7].totalscore() + students[8].totalscore())/3.00));
}
}
这段代码和前一个功能、结构相似,都是输入学生的科目和同时成绩、期末成绩,计算各项平均成绩。主要区别就是输入3个学生的信息,将每个学生的信息封装在一个学生对象中。用两层for循环接收输入的学生信息,第一次循环表示不同的学生,第二层循环表示同一学生的不同科目的成绩,最后调用学生方法即可得到结果。
题目三:7-7 菜单计价程序-1
题目:
某饭店提供4种菜,每种菜品的基础价格如下:
西红柿炒蛋 15
清炒土豆丝 12
麻婆豆腐 12
油淋生菜 9
设计点菜计价程序,根据输入的订单,计算并输出总价格。
订单由一条或多条点菜记录组成,每条记录一行,最后以"end"结束
每条点菜记录包含:菜名、份额两个信息。
份额可选项包括:1、2、3,分别代表小、中、大份)
不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格2。
如果计算出现小数,按四舍五入的规则进行处理。
源码分析;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.*;
public class Main {
public static void main(String[] args) {
Menu menu = new Menu(new Dish[]{
new Dish("西红柿炒蛋", 15),
new Dish("清炒土豆丝", 12),
new Dish("麻婆豆腐", 12),
new Dish("油淋生菜", 9)
});
Order order = new Order();
List<String> notFounds = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if ("end".equals(line)) {
break;
}
String[] lineArray = line.split(" ");
String dishName = lineArray[0];
int portion = Integer.parseInt(lineArray[1]);
Dish dish = menu.searthDish(dishName);
if (dish == null) {
notFounds.add(dishName);
} else {
order.addARecord(dish, portion);
}
}
for (String dishName : notFounds) {
System.out.println(dishName + " does not exist");
}
System.out.println(order.getTotalPrice());
}
}
class Menu {
private Dish[] dishs;
Menu(Dish[] dishs) {
this.dishs = dishs;
}
Dish searthDish(String dishName) {
for (Dish dish : dishs) {
if (dish.getName().equals(dishName)) {
return dish;
}
}
return null;
}
}
class Dish {
String name;
int unit_price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getUnit_price() {
return unit_price;
}
public void setUnit_price(int unit_price) {
this.unit_price = unit_price;
}
public Dish(String name, int unit_price) {
this.name = name;
this.unit_price = unit_price;
}
int getPrice(int portion)
{
float b[] = {1, 1.5f, 2};
return Math.round((unit_price * b[portion - 1]));
}
}
class Record {
Dish d;
int portion;
public Dish getD() {
return d;
}
public void setD(Dish d) {
this.d = d;
}
public int getPortion() {
return portion;
}
public void setPortion(int portion) {
this.portion = portion;
}
public Record(Dish d, int portion) {
this.d = d;
this.portion = portion;
}
int getPrice()
{
return d.getPrice(portion);
}
}
class Order {
private List<Record> records = new ArrayList<>();//保存订单上每一道的记录
int getTotalPrice()
{
int total = 0;
for (Record record : records) {
total += record.getPrice();
}
return total;
}
Record addARecord(Dish dish, int portion) {
Record record = new Record(dish, portion);
records.add(record);
return record;
}
}
这个代码和前两个相比就相对复杂,需要创建多个类。对于初学者来说,想要准确地将每个类中分配合适的量是比较困难的,在这一点上我就遇到了一些问题。
题目四:7-2 课程成绩统计程序-1
题目:
某高校课程从性质上分为:必修课、选修课,从考核方式上分为:考试、考察。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式(可选,如果性质是必修课,考核方式可以没有)三个数据项。
课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
课程性质输入项:必修、选修
考核方式输入选项:考试、考察
课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
以上信息的相关约束:
1)平时成绩和期末成绩的权重默认为0.3、0.7
2)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
3)学号由8位数字组成
4)姓名不超过10个字符
5)课程名称不超过10个字符
6)不特别输入班级信息,班级号是学号的前6位。
2、输出:
输出包含三个部分,包括学生所有课程总成绩的平均分、单门课程成绩平均分、单门课程总成绩平均分、班级所有课程总成绩平均分。
为避免误差,平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
1)学生课程总成绩平均分按学号由低到高排序输出
格式:学号+英文空格+姓名+英文空格+总成绩平均分
如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
2)单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
格式:课程名称+英文空格+平时成绩平均分+英文空格+期末考试平均分+英文空格+总成绩平均分
如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
3)班级所有课程总成绩平均分按班级由低到高排序输出
格式:班级号+英文空格+总成绩平均分
如果某个班级没有任何成绩信息,输出:班级名称+英文空格+ "has no grades yet"
异常情况:
1)如果解析某个成绩信息时,课程名称不在已输入的课程列表中,输出:学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist"
2)如果解析某个成绩信息时,输入的成绩数量和课程的考核方式不匹配,输出:学号+英文空格+姓名+英文空格+": access mode mismatch"
以上两种情况如果同时出现,按第一种情况输出结果。
3)如果解析某个课程信息时,输入的课程性质和课程的考核方式不匹配,输出:课程名称+" : course type & access mode mismatch"
4)格式错误以及其他信息异常如成绩超出范围等,均按格式错误处理,输出"wrong format"
5)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
信息约束:
1)成绩平均分只取整数部分,小数部分丢弃
源码分析:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("java has no grades yet");
System.out.println("数据结构 has no grades yet");
System.out.println("形式与政治 has no grades yet");
}
}
class Score{
int ususalScore;
int finalScore;
}
class Course{
String classID;
}
class Student{
String studentname;
String studentID;
}
class Classroom{
}
参考类图:
这个题目是前三次作业中我遇到的最大的困难,监测点数量较多,题目的需求也较多,我不能很好地将各个类中需要哪些量分析清楚,导致这一题没有能够完成。
三.踩坑心得
第二次作业中“7-8 jmu-java-日期类的基本使用”中我遇到了较大的困难。题目要求通过输入日期判断该年是否闰年,该日期是当年第几天、当月第几天、当周第几天。我最开始的想法是和当初学习C语言时一样,通过构造函数进行判断,后来发现这个过程太多繁琐,耗费了大量的时间与精力。通过查阅资料得知java8中可以直接使用
import·java.time.temporal.ChronoField;
import·java.time.format.DateTimeParseException;
来获取时间间隔等相关计算,遂使用相关语句。但随后发现完全使用long·daysBetween、long monthsBetween、long·yearsBetween所得出的时间间隔与测试用例的时间间隔有所出入,始终不能正确。
这个问题一直保持到了课堂上的讲解和第三次作业。第三次作业的第一题即为这道题的升级。在熟悉了java8日期相关的操作后,使用了
import·java.time.LocalDate;
import·java.time.temporal.ChronoUnit;
import·java.time.temporal.ChronoField;
没有完全使用java自带的时间间隔计算方法,变换了计算方式后,
long·monthinterval·=·secondday.getMonthValue()-firstday.getMonthValue();
long·yearinterval·=·secondday.getYear()-firstday.getYear();
这次变换计算方法后得到了预期的结果
四.主要困难与改进建议
我在这段时间的学习过程中,遇到的最大的问题就是对JAVA基本功能的不了解和对类中操作的不熟悉,在进行作业时,经常碰到一个本来可以通过JAVA8自带的库解决的问题,但我根本不知道有这个功能,导致自己尝试写函数,花费了大量的时间。再就是对类中操作的不熟悉,碰到需要一段较长代码才能实现功能时,在类中我不知道应该从何开始下手,导致较长代码不能有一个开始。
五.总结
作为Java新手,我初步了解了这门强大的编程语言。在学习过程中,我遇到了很多困难,但通过查阅资料和请教他人,我逐渐理解了Java的核心概念,如类、对象。此外,我我意识到仅仅跟随课堂知识进行学习时远远不够的,经常就会碰到这个知识点还没讲到,而我已经需要运用这个知识的相关内容。在写题目的过程中进行学习、查找资料耗费了大量的时间。我想更应该将知识的学习提前,开始自己系统地学习相关的用法、规范,很多时候碰到了问题再来学习时间上就来不及了。