1.前言

(1)OOP训练集01:知识点主要是不同数据类型的输入、处理、应用和输出,以及基本的选择语句和循环语句的应用,还有很基础的Math类和String类的使用,题量稍微有点多,但是都不难。虽然有c语言的语法基础,但因为是第一次接触Java,没那么快就上手,在b站上看了很多网课、看书也看了很久才开始写作业,导致题目集没能及时完成。后来找时间写了一遍,还是比较容易的。

(2)OOP训练集02:知识点的考察和训练集01差不多,题量少了一些。难度一般,主要是最后两道,判断三角形类型和求下一天,稍微有一点难度。这次出现了部分测试点无法通过的问题,几乎每道题都有。提交作业后在csdn里查找后发现,有一些是因为最后的输出没有把double型数据改成float型,题目里没有指明,我不知道为什么要改。

(3)OOP训练集03:开始考察类的创建,权限修饰符的使用等,难度增大了,但这是我前三次写的最好的一次,跟着题目的思路走还是挺清晰的,写的过程中对面向对象有了一些理解,但也存在一些问题。

 

 

2.设计与分析

我只挑出了三道题来分析,这三道是我思路非常清晰而且认真思考的题目,也比较有挑战性。分析过程会依次给出题目、我的思考过程和我的代码。其中也有一些问题,会放在下个板块来说明。

(1)训练集02 7-8 判断三角形类型

 

 

 

我的思路:

由题可知,主要考察选择语句的使用,输出分多种情况,那就基于“已知三角形三边的长度”这一条件开始分析不同情况的特点

非法

不能构成三角形

等边三角形

等腰直角三角形

等腰三角形

直角三角形

一般三角形

三条边取值超过范围

不符合两边相加大于第三边

三边相等

直角边相等&直角边平方相加等于斜边平方&三边之比是1:1:根号2

两边相等

直角边平方相加等于斜边平方

只要不是前面这六种情况,都属于一般三角形

整理出来之后发现问题,这几种情况有相交,比如等边三角形和等腰直角三角形也属于等腰三角形,所以写if-else语句时,要让等边三角形这些特殊情况独立出来。

逻辑运算符如何使用非常重要!!

我的代码:

import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        double a= input.nextDouble();
        double b= input.nextDouble();
        double c= input.nextDouble();
        if(a<1||a>200||b<1||b>200||c<1||c>200){
            System.out.println("Wrong Format");
        }
        else {
            if(a+b<=c||a+c<=b||b+c<=a){
                System.out.println("Not a triangle");
            }
            else {
                if(a==b&&b==c){
                    System.out.println("Equilateral triangle");
                } else if ((a*a+b*b)==c*c||(a*a+c*c)==b*b||(b*b+c*c)==a*a) {
                    if((a/Math.sqrt(2)==b&&a/Math.sqrt(2)==c)||(b/Math.sqrt(2)==a&&a/Math.sqrt(2)==c)||(c/Math.sqrt(2)==a&&c/Math.sqrt(2)==b)){
                        System.out.println("Isosceles right-angled triangle");
                    }
                    else {
                        System.out.println("Right-angled triangle");
                    }
                } else if (a==b||a==c||b==c) {
                    System.out.println("Isosceles triangle");
                } else {
                    System.out.println("General triangle");
                }
            }
        }
    }
}

对于等腰直角三角形和直角三角形的处理,我先用“直角边平方相加等于斜边平方”把所有的直角三角形分出来,再在直角三角形中用“三边之比是1:1:根号2”把等腰直角三角形分出来,剩下的是普通的直角三角形。

但是出了问题:

 

 

测试点里就这个没过,我也不知道为什么orz。

 

(2)训练集03 7-3 定义日期类

 

 

 

 

我的思路:

*先创建Date类,把题目中要求的属性和方法全部写好,像isLeapYear(int year)这种方法先写好空方法,一步一步跟着思路来补。

*Main中输入和创建类不用说,输出格式中需要判断输入非法和日期不存在,那就先写checkInputValidity()。这个方法的返回值是boolean类型,即true(合法)false(不合法),列出可能的情况:

年月日超出合法取值范围

闰年时day超出每月最大天数

平年时day超出每月最大天数

如果这些情况都不满足,那就返回true(输入合法)

ps:写这个方法需要判断是否是闰年,所先把isLeapYear(int year)写好,后面为了简化代码,返回的情况就写成平年返回true,闰年返回false。

*值得一提的是属性里的每月最大日期数组,一开始我并不清楚为什么要写这个属性,写到判断合法性的时候自然而然的想到去用它,如果题目里并没有提示用这个数组,我估计会写得非常复杂。

*输出下一天,开始写getNextDate(),也有多种情况:

12月31日

闰年&月末

平年&月末

其他的日期

year+1

月日固定1月1日

month+1

年不变,day=1

month+1

年不变,day=1

day+1

*最后按合法和不合法在Main中分别输出。

我的代码:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        //输入年月日
        Scanner input=new Scanner(System.in);
        int year=input.nextInt();
        int month=input.nextInt();
        int day=input.nextInt();

        //创建类Date
        Date Date=new Date();
        Date.setYear(year);
        Date.setMonth(month);
        Date.setDay(day);

        //判断是否输入合法
        if(Date.checkInputValidity()){
            Date.getNextDate();
            System.out.println("Next day is:"+Date.getYear()+"-"+Date.getMonth()+"-"+Date.getDay());
        }//输入合法
        else {
            System.out.println("Date Format is Wrong");
        }//输入不合法
    }
}
class Date {
    private int year;
    private int month;
    private int day;
    private int[] mon_maxnum1=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};//平年
    private int[] mon_maxnum2=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年
    public Date() {
    }
    public 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 month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }
    public void setDay(int day) {
        this.day = day;
    }

    public boolean isLeapYear(int year){
        return !(year % 4 == 0 && year % 100 != 0 || year % 400 == 0);//是平年返回true,不是平年返回false
    }

    public boolean checkInputValidity(){
        if(year<1900||year>2000||month<1||month>12||day<1||day>31){
            return false;//超出合法取值
        } else if (isLeapYear(year)&&day>mon_maxnum1[month]) {
            return false;//平年的情况
        } else return isLeapYear(year)||day<=mon_maxnum2[month]; //闰年的情况,三种情况都不满足就返回true
    }

    public void getNextDate(){
        if(month==12&&day==31){
            year=year+1;
            month=1;
            day=1;//一年的最后一天
        }else if(isLeapYear(year)&&day==mon_maxnum1[month]){
            month=month+1;
            day=1;//平年每月最后一天
        } else if ((!isLeapYear(year))&&day==mon_maxnum2[month]) {
            month=month+1;
            day=1;//闰年每月最后一天
        }else {
            day=day+1;//其他的日期
        }
    }
}

 

(3)训练集03 7-4 日期设计类

 

 

 

 

我的思路:

*和7-3一样,先创建DateUtil,属性和方法都写好,题目给出了主方法,就跟着主方法的思路补充完整

*主方法分了三个功能,都用到了checkInputValidity()和isLeapYear(int year),和7-3是一样的可以照搬,三个功能都在方法内调用了showDate(),先按题目要求的格式写好。

*求下n天和前n天沿用7-3题的思路,下n天即是一直求下一天,进行n次循环,前n天即是一直求前一天,进行n次循环。

*两个日期相差的天数是最复杂的,存在三种情况:

两日期相等

第一个日期在第二个日期前面

第一个日期在第二个日期后面

自然而然要用 compareDates(DateUtil date)比较大小,equalTwoDates(DateUtil date)判断是否相等。

比较大小也有三种情况:

年不相等

年相等,月不相等

年月相等,日不相等

计算天数的思路很简单,让第一个日期不断地求下一天或求前一天,直到和第二个日期相等(不相等就是循环条件),需要设置一个整型数据n,每循环一次就自增一次,循环结束时n

就是相差的天数。

代码:主方法

import java.util.Scanner;

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);
        }
    }
}

DateUtil类

class DateUtil {
    private int year;
    private int month;
    private int day;
    private int[] mon_maxNum1=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};//平年
    private int[] mon_maxNum2=new int[]{0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年

    public DateUtil() {
    }
    public DateUtil(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 month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }
    public void setDay(int day) {
        this.day = day;
    }

    //判断year是否为闰年
    public boolean isLeapYear(int year){
        return !(year % 4 == 0 && year % 100 != 0 || year % 400 == 0);//是平年返回true,不是平年返回false
    }

    //检测输入的年、月、日是否合法
    public boolean checkInputValidity(){
        if(year<1820||year>2020||month<1||month>12||day<1||day>31){
            return false;//超出合法取值
        } else if (isLeapYear(year)&&day>mon_maxNum1[month]) {
            return false;//平年的情况
        } else return isLeapYear(year)||day<=mon_maxNum2[month]; //闰年的情况,三种情况都不满足就返回true
    }

    //以“year-month-day”格式返回日期值
    public String showDate(){
        return year+"-"+month+"-"+day;
    }

    //取得year-month-day的下n天日期
    public DateUtil getNextNDays(int n){
        while(n>365){
            if(isLeapYear(year)){
                n=n-365;
                year=year+1;
            }
            else{
                n=n-366;
                year=year+1;
            }
        }
        for (int i = 1; i<=n; i++) {
            if (month == 12 && day == 31) {
                year = year + 1;
                month = 1;
                day = 1;//一年的最后一天
            } else if (isLeapYear(year) && day == mon_maxNum1[month]) {
                month = month + 1;
                day = 1;//平年每月最后一天
            } else if ((!isLeapYear(year)) && day == mon_maxNum2[month]) {
                month = month + 1;
                day = 1;//闰年每月最后一天
            } else {
                day = day + 1;//其他的日期
            }
        }
        showDate();
        return new DateUtil(getYear(),getMonth(),getDay());
    }

    //取得year-month-day的前n天日期
    public DateUtil getPreviousNDays(int n){
        while(n>365){
            if(isLeapYear(year)){
                n=n-365;
                year=year-1;
            }
            else{
                n=n-366;
                year=year-1;
            }
        }
        for(int i=1;i<=n;i++) {
            if (month == 1 && day == 1) {
                year = year - 1;
                month = 12;
                day = 31;//一年的第一天
            } else if (isLeapYear(year) && day == 1) {
                month = month - 1;
                day = mon_maxNum1[month];//平年每月第一天
            } else if ((!isLeapYear(year)) && day == 1) {
                month = month - 1;
                day = mon_maxNum2[month];//闰年每月第一天
            } else {
                day = day - 1;//其他的日期
            }
        }
        showDate();
        return new DateUtil(getYear(),getMonth(),getDay());
    }

    //比较当前日期与date的大小(先后),当前日期<date返回true,反之返回false
    public boolean compareDates(DateUtil date){
        if(year<date.getYear()){
            return true;
        } else if (year==date.getYear()&&month<date.getMonth()) {
            return true;
        } else return year == date.getYear() && month == date.getMonth() && day < date.getDay();
    }

    //判断两个日期是否相等,相等返回true,反之返回false
    public boolean equalTwoDates(DateUtil date){
        return year==date.getYear()&&month==date.getMonth()&&day==date.getDay();
    }

    //求当前日期与date之间相差的天数
    public int getDaysofDates(DateUtil date){
        int n=0;//相差的天数
        if(equalTwoDates(date)){//相等
            return n;
        } else if (compareDates(date)) {//当前天数<date
            while(!equalTwoDates(date)){
                if(month==12&&day==31){
                    year=year+1;
                    month=1;
                    day=1;//一年的最后一天
                }else if(isLeapYear(year)&&day==mon_maxNum1[month]){
                    month=month+1;
                    day=1;//平年每月最后一天
                } else if ((!isLeapYear(year))&&day==mon_maxNum2[month]) {
                    month=month+1;
                    day=1;//闰年每月最后一天
                }else {
                    day=day+1;//其他的日期
                }
                n++;
            }
            return n;
        } else{//当前天数>date
            while(!equalTwoDates(date)){
                if (month == 1 && day == 1) {
                    year = year - 1;
                    month = 12;
                    day = 31;//一年的第一天
                } else if (isLeapYear(year) && day == 1) {
                    month = month - 1;
                    day = mon_maxNum1[month];//平年每月第一天
                } else if ((!isLeapYear(year)) && day == 1) {
                    month = month - 1;
                    day = mon_maxNum2[month];//闰年每月第一天
                } else {
                    day = day - 1;//其他的日期
                }
                n++;
            }
            return n;
        }
    }
}

 

 

3.踩坑心得

(1)首先就是训练集02的7-5学号识别题

 

 

一开始我的代码是这么写的(截了一部分)

于是本该正常输出结果的却判定为非法输入

 

 

(目的是输出入学年份为2008年)

思考一番才知道如果08011103作为int型数据输入,会被判定为八进制,不能用我上面写的代码判断是否为八位数字输入,要改成string类型输入。

 

(2)关于第二次题目集中需要类型转换的情况,我还是不明白为什么。

例如7-1长度质量计量单位转换

 

 

最后的输出:

????为啥要转成float型???

我不能理解。

 

(3)题目集03的7-4题中有很多的情况要判断,让人非常头疼。

比如这些:

 

 

前面的题目情况相对简单,就没有注意用注释,这道题复杂起来让人头昏脑涨,在每一种判断的情况后加上注释,我的思路就变得非常清晰。

 

(4)题目集03 7-4题在第一次提交的时候出现了运行超时的问题:

看了下n天和前n天部分的代码并调试后发现,当n很大时——

 

 

这种写法就会使循环进行很多很多次。因此为了减少循环次数,我让n>365的情况直接减去365,年份加一或减一,变成一年以内的循环,就能减少循环次数——

 

 

以后写代码的时候需要注意简化循环的次数!!!

 

(5)最后依然是题目集03 7-4:

之前这段代码里所有的getyear()前没有加上"date.",导致判断出错,答案错误。在写带参数的方法时一定要分清参数的来源!

 

4.改进建议

其它题目没有想到,只针对训练集03 7-4日期类设计题,关于三个功能的实现运用了循环,求下n天和前n天稍微减少了循环次数,而求两个日期的相差天数没有简化循环,我认为有更好的写法来减少循环,以后写代码也应该多往更简单的方法去思考。

 

5.总结

前三次作业让我迅速了解到Java的一些基本语法的运用,以及基础的面向对象知识,对面向对象编程和面向过程编程的区别有了很多的思考。在我看来,面向对象编程我的思路更清晰,在写代码时没有当初学c语言时那么混乱,这对我应该也算一种激励。

但由于我急于完成作业,Java语法的自学基本上是哪里不会看哪里,从前两次题目集的情况来看,效果很差,我对不同类型的数据处理存在盲区,尤其是字符型和字符串型,很多题目都是部分正确,关于这方面的全面的完整的学习和查缺补漏刻不容缓。

还有一些建议是希望老师能讲一讲大家在面向对象编程过程中共同的容易出问题的地方,语法上的问题也希望能提一嘴,平时写的题目集如果有时间能讲一下最好了,没时间的话希望可以知道之前写的题目的测试点,也好自己调试找到错误的地方。

作业的话我觉得难度正常有一些挑战性,虽然说对我这种菜鸟有些杀脑细胞。。。我对身边事物是如何运转的挺感兴趣的,也自己有思考过,所以希望以后布置的题目主题可以更贴近日常生活,比如,咳咳,训练集02的7-4就很不错......