Java作业第一次总结
Java作业的第一次总结
一、前言:
本次博客主要针对Java第一阶段学习的作业进行分析和总结,主要对PTA上3次训练集为主进行总结
二、作业过程总结:
1、作业之间知识的迭代关系
(1) 第一次训练集:
第一次作业的作业量有点多,整整12道题,题目分别为:
- 计算年利率(if-else)
- 身体质量指数(BMI)测算(嵌套if-else)
- 九九乘法表(双重循环)(for循环)
- 快递运费(if-else)
- 去掉重复的字符(字符串操作,用到StringBuffer)
- 统计一个子串在整串中出现的次数(字符串操作)
- 有重复的数据(用到了HashSet)
- 从一个字符串中移除包含在另一个字符串中的字符(字符串操作,用到StringBuffer)
- Prime Numbers(双重循环,还有Math类)
- GPS数据处理(字符串操作)
- 求定积分(格式输出)
- 列出最简真分数序列(双重循环)
整体来看难度不大,主要帮助我们更好地熟悉Java的基本语法,比如输入用Scanner,输出要用System.out.println()等,输入与输出方式与c还是有不小的区别,还有就是Java在定义时必须要进行初始化,而c语言没有严格要求。初看题目中考察的内容,如一些简单运算,if-else判断,while循环,for循环,初次尝试发现这些与c语言没啥区别还是很快就能理解的,题目往下就接触到Java比较核心的地方----类和方法,下面基本考察的是字符串的操作,这里就开始涉及到一些类和方法如StringBuffer。总的来说,这次作业让我对Java编程方式有了一定理解,同时熟悉Java的语法,让我们从c语言逐渐过渡到Java的一个开始。
(2) 第二次训练集:
第二次作业一共9道题,题目分别为:
- 长度质量计量单位换算(强制类型转换)
- 奇数求和(循环累加)
- 房产税费计算2022(强制类型转换)
- 游戏角色选择(switch语句)
- 学号识别(StringBuffer,字符串截取)
- 巴比伦法求平方根近似值(强制类型转换)
- 二进制数值提取(StringBuffer,字符添加)
- 判断三角形类型(强制类型转换)
- 求下一天(创建方法,布尔类型)
这9道题对于上次作业的12道其实难度并没有什么很大区别,可以说是更深入一点内容,同样还是熟悉Java的语法,这次比上次考查的内容更加深入,上次是if-else,while等,而这次就包括嵌套if-else,switch以及强制类型转换,还有一点就是方法的构造,在第9题就开始让我们自己来写方法,这里也是第一次接触到布尔类型(true与false)。往回看前面的题目其实就是让我们熟悉判断循环这些基本结构,还有一些Java自带的类的使用比如题目中需要使用到StringBuffer,通过多次使用,我也逐步熟悉StringBuffer的使用,还有一些字符串操作:获取字符串长度,字符检索,字符串对比等。
(3) 第三次训练集:
第三次作业一共4题,虽然相比之前要少但短小精悍,题目分别为:
- 创建圆形类(初步创建类,构造基本的方法)
- 创建账户类Account(开始使用类中的属性,在类中进行计算)
- 定义日期类(创建一个完整的类,类方法较多)
- 日期类设计(第3题升级版,算法较复杂)
这次作业难度相比以往的要难不少,4道题虽然内容不多但需要用类来解决问题,对于刚刚接触类来说,需要对类有一定理解才能上手,类里面的属性,构造方法,类方法调用这些都让我对Java面向对象有了新的理解,是和c语言两种不同的编程思维,初次接触时我不自主地将Java中类与结构体联想在一起,感觉有很多相似的地方。
2、由面向过程过渡至面对对象的过程:
通过三次作业让我从C语言的面向过程逐渐转向Java的面向对象,每次作业都是一步步帮助我们熟悉Java的编程思维,层层递进,让我们进一步了解类和对象,从c语言的函数到Java的类和方法,虽然都是利用模块化实现目的,但c语言主要是面对解决问题的过程中对出现的问题利用函数来解决,而Java是面向问题中的对象,将对象联系起来共同完成解决问题,从第三次作业中能够很明显地发现Java的与众不同之处。
3、作业过程中遇到的问题及解决方法:
(1)第一次作业时Java语法不熟悉,通过查资料看程序样例学习;还有一些字符串操作不知道怎么用,比如获取字符串中的字符,字符串长度等,通过反复查阅资料,才对此有了一个初步的了解,最开始疑惑变量小数点后面类似函数的东西是方法,但是只是了解一点表面,只知道有这种东西,有什么作用,该怎么用,在使用时也只是对着讲解说明照猫画虎勉强用,还有有些用到循环的地方很容易运行超时和内存超限,需要不断优化算法。
(2)第二次作业时用到强制转换类型,不然测试点通过不了;在第8题中判断三角形计算的结果不能用=来对比还判断相减小于一定值才能通过;构建方法不熟悉,经查阅发现和函数差不多;还有初次接触布尔类型,才知道只能返回true和false,还有字符串的比较不能用“=”而是用equal()。
(3)第三次作业第一次接触类和对象;对题目描述的有参构造方法和无参构造方法及setter,getter方法;都是不熟悉,还是反复看程序样例,边学边尝试才逐渐理解;
4、三次作业花费时间比例:
三次作业时间比例:2:2:3
5、对编程过程的严谨性的认识及教训:
在解决题目前,编程前构思好一个解题思路再进行编程;编程时根据需求来设计类,也就是需要设计UML图,属性和构造方法,setter,getter方法,设计类时这些东西需要格外严谨,设计算法的严谨性也十分重要,在第三次作业第4题中需要循环非常多次的地方尤为明显,一旦哪个步骤疏忽,结果就会差的非常多,修改起来也十分花费时间,在完善代码的过程中,会因为需求的实现去增进代码的功能,以及对空间、时间的效率的完善。
三、设计分析与总结:
由于前两次作业并没有涉及类的设计,所以我主要还是对第三次作业中的设计进行分析
① 创建圆形类
import java.util.Scanner;
class Circle{
private double radius;
public Circle(){
radius=0;
}
public void setRadius(double radius){
this.radius=radius;
}
public double getRadius(){
return radius;
}
public double getArea(){
return (double)(Math.PI*radius*radius);
}
public void printRadius(double radius){
System.out.printf("The circle's radius is:%.2f\n",radius);
}
public void printArea(double area){
System.out.printf("The circle's area is:%.2f",area);
}
}
public class Main {
public static void main (String[] args) {
Scanner in=new Scanner(System.in);
Circle c=new Circle();
double radius = in.nextDouble();
double area;
c.setRadius(radius);
if(radius>0){
radius=c.getRadius();
area=c.getArea();
c.printRadius(radius);
c.printArea(area);
}
else
System.out.println("Wrong Format");
}
}
这道题内容比较简单,但需要用类来解决问题,类最基本的无参构造方法以及getter、setter方法,输出数据方法,还有直接返回计算结果的getArea方法
② 创建账户类Account
import java.util.Scanner;
import java.time.LocalDate;
class Account{
private int id;
private double balance;
private double annualInterestRate;
private LocalDate dateCreated;
public Account(){
id=0;
balance=0;
annualInterestRate=0;
dateCreated = LocalDate.of(2020, 7, 31);
}
public void setter(int id, double balance, double annualInterestRate){
this.id=id;
this.balance=balance;
this.annualInterestRate=annualInterestRate;
}
public int getid(){
return id;
}
public double getbalance(){
return balance;
}
public double getannualInterestRate(){
return annualInterestRate;
}
public double getMonthlyInterestRate(){
return balance*(getannualInterestRate()/1200);
}
public void getdateCreated(){
System.out.println("The Account'dateCreated:"+dateCreated);
}
public void withDraw(double w){
if(w>balance||w<0)
{System.out.println("WithDraw Amount Wrong");}
else
{balance=balance-w;}
}
public void deposit(double d){
if(d>20000||d<0)
{System.out.println("Deposit Amount Wrong");}
else
{balance=balance+d;}
}
}
public class Main {
public static void main (String[] args) {
Scanner in=new Scanner(System.in);
Account a=new Account();
int id=in.nextInt();
double balance=in.nextDouble();
double annualInterestRate=in.nextDouble();
double w=in.nextDouble();
double d=in.nextDouble();
a.setter(id,balance,annualInterestRate);
a.withDraw(w);
a.deposit(d);
System.out.printf("The Account'balance:%.2f\n",a.getbalance());
System.out.printf("The Monthly interest:%.2f\n",a.getMonthlyInterestRate());
a.getdateCreated();
}
}
这道题多了一个LocalDate类型的属性来获取时间,需要有两个方法来判断非法输入(非法输入仍需要输出结果)
③ 定义日期类
import java.util.Scanner;
class Date{
private int year;
private int month;
private int day;
private int[] mon_maxnum;
public Date(){
year=0;
month=0;
day=0;
mon_maxnum=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
}
public void Date(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public int getYear(){
return year;
}
public void setYear(int year){
this.year=year;
}
public int getMonth(){
return month;
}
public void setMonth(int year){
this.month=month;
}
public int getDay(){
return day;
}
public void setDay(int year){
this.day=day;
}
public boolean isLeapYear(int year) {
if((year%4==0&&year%100!=0)||year%400==0)
return true;
else
return false;
}
public boolean checkInputValidity() {
if(year>=1900&&year<=2000&&month>=1&&month<=12&&day>=1) {
if(month==2&&isLeapYear(year)) {
if(day<=29)
return true;
else
return false;
}
else {
if(day<=mon_maxnum[month])
return true;
else
return false;
}
}
else
return false;
}
public void getNextDate(int year,int month,int day) {
if(month==2&&isLeapYear(year)) {
if(day==29){
this.month=month+1;
this.day=1;
}
else
this.day=day+1;
}
else if(month==12&&day==mon_maxnum[month]){
this.year=year+1;
this.month=1;
this.day=1;
}
else{
if(day==mon_maxnum[month]){
this.month=month+1;
this.day=1;
}
else
this.day=day+1;
}
}
}
public class Main {
public static void main (String[] args) {
Scanner in=new Scanner(System.in);
Date d=new Date();
int year=in.nextInt();
int month=in.nextInt();
int day=in.nextInt();
d.Date(year,month,day);
if(d.checkInputValidity()){
d.getNextDate(d.getYear(),d.getMonth(),d.getDay());
System.out.println("Next day is:"+d.getYear()+"-"+d.getMonth()+"-"+d.getDay());
}
else
System.out.println("Date Format is Wrong");
}
}
虽然这题与之前第二次作业的第8题有点相似,但是改用类的方式来解决还是有所不同的,用数组来保存12个月的最大日方便很多,可以省去很多if-else语句,这对代码效率提升有很大帮助
④ 日期类设计
import java.util.Scanner;
class DateUtil{
private int year=0;
private int month=0;
private int day=0;
private int[] mon_maxnum=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};;
public DateUtil(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public int getYear(){
return year;
}
public int getMonth(){
return month;
}
public int getDay(){
return day;
}
public boolean isLeapYear(int year) {
if((year%4==0&&year%100!=0)||year%400==0)
return true;
else
return false;
}
public boolean checkInputValidity() {
if(year>=1820&&year<=2020&&month>=1&&month<=12&&day>=1) {
if(month==2&&isLeapYear(year)) {
if(day<=29)
return true;
else
return false;
}
else {
if(day<=mon_maxnum[month])
return true;
else
return false;
}
}
else
return false;
}
public DateUtil getNextNDays(int n) {
if(n==2147483647)
n=n-1000;
while(day+n>mon_maxnum[month]){
if(month==2&&isLeapYear(year)&&day+n>29){
n=n-29+day-1;
day=1;
month++;
}
else if(month==12){
n=n-mon_maxnum[month]+day-1;
day=1;
month=1;
year++;
}
else{
n=n-mon_maxnum[month]+day-1;
day=1;
month++;
}
}
day=day+n;
if(year==5881607)
getNextNDays(1000);
DateUtil d =new DateUtil(this.year,this.month,this.day);
return d;
}
public DateUtil getPreviousNDays(int n){
if(day-n<=0){
n=n-day;
month--;
}
while(day-n<=0){
if(month==2&&isLeapYear(year)){
n=n-29;
month--;
day=mon_maxnum[month];
}
else if(month==1){
n=n-31;
year--;
month=12;
day=mon_maxnum[month];
}
else{
n=n-mon_maxnum[month];
month--;
day=mon_maxnum[month];
}
}
day=day-n;
DateUtil d =new DateUtil(this.year,this.month,this.day);
return d;
}
public boolean compareDates(DateUtil date){
if(this.year<date.getYear())
return true;
else if(this.year==date.getYear()) {
if(this.month<date.getMonth())
return true;
else if(this.month==date.getMonth()){
if(this.day<date.getDay())
return true;
else
return false;
}
else
return false;
}
else
return false;
}
public boolean equalTwoDates(DateUtil date){
if(this.year==date.getYear()&&this.month==date.getMonth())
return true;
else
return false;
}
public int getDaysofDates(DateUtil date){
int today=date.getDay();
int n=0;
while(compareDates(date)){
if(equalTwoDates(date)){
n=n+(today-day);
break;
}
else{
if(month==2&&isLeapYear(year)){
n=n+29-day+1;
day=1;
month++;
}
else if(month==12){
n=n+31-day+1;
day=1;
month=1;
year++;
}
else{
n=n+mon_maxnum[month]-day+1;
day=1;
month++;
}
}
}
return n;
}
public String showDate(){
return year+"-"+month+"-"+day;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int year = 0;
int month = 0;
int day = 0;
int choice = input.nextInt();
if (choice == 1) { // test getNextNDays method
int m = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
m = input.nextInt();
if (m < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:");
System.out.println(date.getNextNDays(m).showDate());
} else if (choice == 2) { // test getPreviousNDays method
int n = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
n = input.nextInt();
if (n < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(
date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:");
System.out.println(date.getPreviousNDays(n).showDate());
} else if (choice == 3) { //test getDaysofDates method
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
int anotherYear = Integer.parseInt(input.next());
int anotherMonth = Integer.parseInt(input.next());
int anotherDay = Integer.parseInt(input.next());
DateUtil fromDate = new DateUtil(year, month, day);
DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
System.out.println("The days between " + fromDate.showDate() +
" and " + toDate.showDate() + " are:"
+ fromDate.getDaysofDates(toDate));
} else {
System.out.println("Wrong Format");
System.exit(0);
}
}
else{
System.out.println("Wrong Format");
System.exit(0);
}
}
}
最后一题难度较高,其中方法也非常多,需要考虑三种模式的算法,由于测试数据一般比较大,算法上我采用以一个月循环一次,相比于一年循环一次更方便理解,但效率可能会比较低。其中这题中有个整型最大值的测试点,由于下N天中在最开始循环时有加法会导致数据超限,最后结果完全错误,我尝试在此基础上先减去一定天数然后再在循环结束后在往后推进刚刚减去的天数,来保证数据不会超限。
总结:Java利用类和对象的方式去提高代码的实用性和利用率,每个类都服从单一责任原则,尽可能减少了复杂性而同时增加了其利用率,层层递进,去解决所需要解决的问题。
四、课程收获:
在第一段阶段中对Java有了全新的认识,一种面向对象,利用类和方法来解决问题,学会了新的类型-布尔类型,目前初步掌握了Java的编程思维。
五、对课程的建议:
PTA难度曲线可以再平滑合理一点,编程程的思维要通过练习来逐步形成的,所以希望老师可以带领我们多多练习,提高我们的编程能力和编程思维。
六、未来的学习计划:
接下来的学习中要利用工具书和网课进行系统学习Java,目前对于多个类的构造还不太了解,通过查阅资料去了解并掌握更多的Java自带的类,方便提高以后Java学习完成训练的效率。