南昌航空大学BLOG-JAVA前三次作业总结

发布时间 2023-10-07 09:58:16作者: 0721大师绫地宁宁

一.前言

(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的核心概念,如类、对象。此外,我我意识到仅仅跟随课堂知识进行学习时远远不够的,经常就会碰到这个知识点还没讲到,而我已经需要运用这个知识的相关内容。在写题目的过程中进行学习、查找资料耗费了大量的时间。我想更应该将知识的学习提前,开始自己系统地学习相关的用法、规范,很多时候碰到了问题再来学习时间上就来不及了