第二次Blog作业

------------恢复内容开始------------

前言

这三次的实验结合前面所学的知识点并进阶了,主要熟练Java面向对象的三大特点:封装、继承、多态的使用。围绕着这三大特点,除此之外还充斥着其他知识点,如:练习类的构造方法、方法的调用、参数传递,对象的构造与使用、练习循环结构、控制结构、练习数据的输入与输出、学习编写结构清晰、逻辑正确、功能完善的Java代码、对于Java当中的基础语法知识点进行错误探查,从而达到掌握好知识点的水平

设计与分析

7-1 水文数据校验及处理 (50 分)
 

使用Java中的字符串处理类以及正则表达式对输入字符串数据进行合法性校验及计算。(具体需求参见附件 2021-OO第04次作业-1指导书V1.0.pdf )

输入格式:

假定分水口门的数据上报时是采用人工输入的方式,每一行代表一个整点时刻的分水数据,各数据之间采用“|”符号进行分隔,每次可以输入多条数据,直到遇到用户输入“exit”为止,每一行输入数据共包含五部分:测量时间、目标水位、实际水位、开度(包含目标开度和实际开度,以“/”分隔)、流量。 各数据格式要求如下:

  1. 测量时间:格式为“年/月/日 时:分”,其中年份取值范围为[1,9999],“月”与“日”为一位数时之前不加“0”,日期与时间之间有一个空格,“时”与“分”之间采用冒号分隔(英文半角),“时”为一位数时之前不加“0”,“分”始终保持两位,且始终为“00”。注意:“时”数必须是24小时进制中的偶数值。
  2. 目标水位、实际水位、流量:均为实型数,取值范围为[1,1000), 小数点后保留1-3位小数或无小数(也无小数点)
  3. 目标开度、实际开度:实型数,取值范围为[1,10),必须保留2位小数,两个开度之间用“/”分隔

知识点:这一道题目主要使用的知识就是对于自字符串信息的处理,而这一点再未来开发中也是极为重要的,原因:不管是在现实社会中还是再任何地方都是具有大量数据的,而且基本是以字符串类型的数据处理,本题对于字符串的处理就会需要使用正则表达式来处理信息,正则表达式再批量处理相似类型的数据是非常有作用的,处理的速度以及能力都是非常强大的一种存在。       

正则表达式:就是匹配数据的一种自定义类型的表达式,是自己根据字符串的的特点来自己定义,对于文本信息的处理分析、分段裁剪的操作,从而得到你所需要的信息        详细分析题解:本题中题目明确了是对于水文信息的检验和处理,那么就涉及到了你所输入的信息是不是符合正确的格式,当中你所输入的水文信息是错误的形式输入那么程序需要提示出你输入的水文信息是再哪里出现了错误,这样可以给予工组人员提示从而达到即使快速的修改,这大大的节省了人力。当你所输入的水温信息完全没有错误的时候就饿可以输出之前处理水文信息处理的结果,所以在这里就是具有很重要的一点就是需要再检测的时候设置中间变量来赋值说明你的数据是由错误的【这一点是给程序的,在后面判断就可断定是不是要输出处理数据的结果了】,而在这里就可以通过常用的方式布尔Boolean类型来设置中间的处理结果的判断。注意:这里不可以使用return语句直接退出程序,即使你是不需要输出处理数据的结果,但是你需要判断每一段水文信息是在哪里出现了错误。在这里可以使用java当中的方法来进行对于字符串进行分割进行片段的分析处理,这样简化了处理的代码能力。

import java.util.ArrayList;

import java.util.Collection;

import java.util.Iterator;

import java.util.Scanner;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {

        int f1 = 0;int f2 = 0;int f3 = 0;int f4 = 0;int f5 = 0;int f6 = 0;

        Double totalWaterFlow = 0.0;

        Double muBiao = 0.0;

        Double shiJi = 0.0;

        int sumOut = 0;

        int hasWrong = 0;int oneHasWrong = 0;

        String str = "2015/8/2 6:00|133.840|133.080|11.11/1.11|72.8a0";

        Scanner input = new Scanner(System.in);

        Double maxShuWei = 0.0;

        ArrayList c = new ArrayList();/* 创建集合数组对象 */

        String news = input.nextLine();

        while (!(news.equals("exit"))) {  c.add(news);news = input.nextLine();  }

        //c.add("exit");

        Iterator t =c.iterator();

        for(int ii =0; ii < (c.size()); ii++){

            oneHasWrong = 0;sumOut=0;

            Object obj = t.next();

            if(obj instanceof  String){str = ((String)obj).trim();}

            if(str.matches("^\\s*|\\s*$")) {                    //判断连续输入为空

            System.out.println("Max Actual Water Level:0.00");          //判断连续输入为空

            System.out.println("Total Water Flow:0.00");

        }

            String[] pattern = {"([0-9]+)(\\/)([0-9]+)(\\/)([0-9]+)(\\s)([0-9]+)(:)([0-9]+)",

                    "(\\|)((\\s*)?)([0-9]+)(\\.?)([0-9]+)",

                    "(\\|)([0-9]+)(\\.?)([0-9]+)(\\/)([A-Za-z0-9]+)(\\.?)([0-9]+)"};

            Pattern r = null;  String[] s = new String[5];  int j = 0;  String temp = str;

            for (int i = 0; i < 5; i++) {

                if(i == 0) {

                    r = Pattern.compile(pattern[0]);

                 }else if (i == 3) {

                    r = Pattern.compile(pattern[2]);

                 }else {

                    r = Pattern.compile(pattern[1]);

                }

                Matcher m = r.matcher(temp);

                if(m.find()) { s[j] = m.group(); temp = temp.substring(s[j].length());j++;}

            }

            //if(j != 5){System.out.println("Wrong Format"); System.out.println("Data:" +str); System.exit(0);}

            int[] monthDay = {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

            for (int i = 0; i < j; i++) {

                if(i == 0){

                    s[i] = s[i].trim();

                    String regular = "((([1-9][0-9]{0,3}))/((((1[0-2]|[1-9]))/(([1-2][0-9]|30|[1-9])))) ((([02468]|1[02468]|2[02]|):00)))";

                    if(!s[i].matches(regular))

                        { System.out.println("Row:"+(ii+1)+",Column:1Wrong Format");f1 = 1; }

                }

                if(i == 1){

                    /* 还用正则表达式来求  |133.8400  */

                    s[i] = s[i].substring(1);

                     s[i] = s[i].replaceAll(" ","");

                    String regular = "[1-9]([0-9]?)([0-9]?)(\\.)?[0-9]([0-9]?)([0-9]?)";

                    if(!s[i].matches(regular))

                        { System.out.println("Row:"+(ii+1)+",Column:2Wrong Format");f2 = 1; }

                }

                if(i == 2){

                    // |133.070

                    s[i] = s[i].substring(1);

                    s[i] = s[i].replaceAll(" ","");

                    String regular = "[1-9]([0-9]?)([0-9]?)(\\.)?[0-9]([0-9]?)([0-9]?)";

                    if(!s[i].matches(regular))// 不满足就是输出错误

                        { System.out.println("Row:"+(ii+1)+",Column:3Wrong Format");f3 = 1; }

                    if(f3 == 0 && Double.parseDouble(s[i]) > maxShuWei){

                        maxShuWei = Double.parseDouble(s[i]);

                    }

                }

                if(i == 3){

                    // |1.11/1.21

                    s[i] = s[i].substring(1);

                     s[i] = s[i].replaceAll(" ","");

                    String[] mbf = s[i].split("/");// mbf 每部分  其实就两部分,目标开度、实际开度

                    for (int k = 0; k < mbf.length; k++) {

                        if(k == 0){// 目标开度 --> |1.11

                            String regular = "[1-9](\\.)?[0-9]?([0-9]?)";

                            if(!mbf[k].matches(regular))// 不满足就是输出错误

                                { System.out.println("Row:"+(ii+1)+",Column:4Wrong Format");f4 = 1; }

                            else

                                { muBiao = Double.parseDouble(mbf[k]);}

                        }

                        if(k == 1) {// 实际开度 --> 1.21

                            String regular = "[1-9](\\.)?[0-9]?([0-9]?)";

                            if(!mbf[k].matches(regular))// 不满足就是输出错误

                                { System.out.println("Row:"+(ii+1)+",Column:5Wrong Format");f5 = 1; }

                            else

                                { shiJi = Double.parseDouble(mbf[k]); }

                        }

                    }

                    if(shiJi > muBiao)  sumOut++;

                }

                if(i == 4){

                    // |75.780

                    s[i] = s[i].substring(1);

                     s[i] = s[i].replaceAll(" ","");

                    String regular = "[1-9]([0-9]?)([0-9]?)(\\.)?[0-9]([0-9]?)([0-9]?)";

                    if(!s[i].matches(regular))

                        { System.out.println("Row:"+(ii+1)+",Column:6Wrong Format");f6 = 1; }

                    if(f6 == 0){/* 求出流量,再加到总流量里去 */

                        Double flow = Double.parseDouble(s[4]);

                        totalWaterFlow = totalWaterFlow + 2*60*60*flow;

                    }

                }

            }

            if(f1==0 && f2==0 && f3==0 && f5 == 0 && f4 ==0 && f6==0 && shiJi > muBiao)// 就说明开度出现了问题就提示错误

             {

                 for (int i = 0; i < sumOut; i++)

                    { System.out.println("Row:"+(ii+1)+" GateOpening Warning"); }

             }

            if(f1==1 || f2==1 || f3==1 || f4==1 || f5==1 || f6==1){ hasWrong++;  oneHasWrong++; }

            if(oneHasWrong != 0) System.out.println("Data:"+str);

            f1 = 0;f2=0;f3 = 0;f4=0;f5=0;f6=0; oneHasWrong = 0;

        }

        if(hasWrong == 0){  System.out.println("Max Actual Water Level:" +String.format("%.2f",+maxShuWei));/* 输出最大的水位信息 */

            System.out.println("Total Water Flow:" +String.format("%.2f",+totalWaterFlow));}

    }

    public static boolean isLeapYear(int year){  return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; }

}

No2:

 

import java.util.Scanner;

 

/**

 

 

2、       日期问题面向对象设计(聚合一) (35 分)

题目详细:

              设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

 

 

 

应用程序共测试三个功能:

  1. 求下n天
  2. 求前n天
  3. 求两个日期相差的天数

           知识点:这里主要就是对于类的设计,当中属性、方法完成相应的功能,本题与上一次发布的功能都是一样的,并且使用的知识点大致是一样的,只是本题中增加了知识点是使用类来设计完成程序,这很重要呀,类可是java程序的重要特点。对于类的设计就要主要到封装、继承、多态的使用,这就很好运用到了三大特点。使用了这三大特点就会使程序更加的健壮,功能更灵活,将来对于代码的改动也会更加简易。

           题目详细分析:本题中需要用户自己选择供能,那么就需要这几功能模块,就可以使用switch语句来完成,通过选择的不同进入不同的方法或则类当中执行不同的方法从而达到所想要的效果。,进入类当中,那么类当中就需要完成相应的属性方法的定义,以及方法的实现,对于方法的实现就需要使用到不同的方法,计算方式来完成计算结果的返回到主程序当中。注意了:再进行相应的方法当中计算结果之前需要检验用户输入的日期信息是不是正确合法的,非法输入的话那就不需要进行计算处理了。

运行结果:

输入:

 

 

 

输出:

 

 

 



运行结果:

样例1:

 

样例2:

 

样例3:

 

 

 



样例1:

 

样例2:

 

样例3:

 

题目集4的代码区域:

     No1:



 * 需求:求n天后日期

 *      求n天前日期

 *      求两个日期之差天数

 */

public class Main {

    /**

     * 在main单中如何·调用方法

     *      - 输入选择是什么功能

     *      - 进入相应的语句进行判断

     *          * 首先是输入日期

     *          * 其次是判断日期是不是正确合法

     *          * 在来就是进行相应的语句条件确认

     */

    public static void main(String[] args) {

        Scanner s = new Scanner(System.in);

        int userChoice = s.nextInt();

        // 创建计算对象

        if(userChoice == 1){

            // 进入第一种状态:计算下n天的日期

            // 先输入日期

            int year = s.nextInt(); int month = s.nextInt(); int day = s.nextInt();

            // 输入n天要开始计算了

            int n = s.nextInt();

            // 创建第一个日期对象

            DateUtil du = new DateUtil(year,month,day);

            // 在检查日期是否合法

            if(!du.checkInputValidity()){

                // 不正确,提示,退出程序

                System.out.println("Wrong Format");

                System.exit(0);

            }

            // 调用方法,开始计算,就是传参 n

            // 创建对象来接收这个返回值

            DateUtil date = du.getNextNDays(n);

            // 接下来就是格式化输出答案,我采用的是重写toString方法

            System.out.println(date);

        }else if(userChoice == 2){

            // 进入第二种状态:计算前n天的日期

            // 先输入日期

            int year = s.nextInt(); int month = s.nextInt(); int day = s.nextInt();

            // 输入n天要开始计算了

            int n = s.nextInt();

            // 创建第一个日期对象

            DateUtil du = new DateUtil(year,month,day);

            // 在检查日期是否合法

            if(!du.checkInputValidity()){

                // 不正确,提示,退出程序

                System.out.println("Wrong Format");

                System.exit(0);

            }

            // 调用方法,开始计算,就是传参 n

            // 创建对象来接收这个返回值

            DateUtil date = du.getPreviousNDays(n);

            // 接下来就是格式化输出答案,我采用的是重写toString方法

            System.out.println(date);

        }else if(userChoice == 3){

            // 进入第三种状态:计算下两个日期是天数差

            // 先输入日期

            int year = s.nextInt(); int month = s.nextInt(); int day = s.nextInt();

            // 创建第一个日期对象

            DateUtil du = new DateUtil(year,month,day);

            // 在输入日期

            int year1 = s.nextInt(); int month1 = s.nextInt(); int day1 = s.nextInt();

            // 创建第一个新的日期对象

            DateUtil date = new DateUtil(year1,month1,day1);

            // 在检查日期是否合法

            if(!du.checkInputValidity() || !date.checkInputValidity()){

                // 不正确,提示,退出程序

                System.out.println("Wrong Format");

                System.exit(0);

            }

            // 调用方法,开始计算,就是传参data

            // 创建对象来接收这个返回值

            /**

             * 1、在对比两个日期是不是相等的

             *      - 相等就直接输出0推出程序

             *  2、先对比啦两个日期的大小

             *     - 前小后大就交换

             *

             */

            if(du.equalsDates(date)){

                // 说明两个日期相等

                System.out.println(0);

                System.exit(0);

            }

            // 到这里就不相等,那比较交换

            // 返回 true就是前比后大    返回 false就是前比后小

            if(!du.compareDate(date)){

                // 说明前比后小,那就交换

                DateUtil temp = new DateUtil();

                temp = du; du = date; date = temp;

            }

            // 到这就正常的去调用方法,接受返回值 int

            int sumDay = du.getDaysofDates(date);

            System.out.print(sumDay);

        }else{

            // 错误选择就是提示一下,退出程序

            System.out.println("您做出的选择有误!!!");

            return;

        }

    }

}

 

// DateUtil类

/*

因该有的东西:

    - 构造方法、set and get方法

    - 计算n天数的日期方法

        * 前n天

        * 后n天

    - 计算两个日期之间相差的天数方法

        * 这里就是看main方法当中的调用问题,反正我先把这些方法都写进入

    - 判断闰年的方法

        * 判断闰年了还要判断月份的问题是【2月】 还是 【非2月】

    - 判断输入的日期是是否合法

    -

//3 2014 2 14 2020 6 14

 */

class DateUtil{

    private int year;

    private int month;

    private int day;

    // 定义为非闰年的每月天数

    int[] monthDay = {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // 重写toString方法

 

    @Override

    public String toString() {

        return year + "-" + month + "-" + day;

    }

 

    // 无参构造方法

    public DateUtil() { }

    // 有参构造方法

    public DateUtil(int year, int month, int day) {

        this.year = year;

        this.month = month;

        this.day = day;

    }

    // set and get

    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){

        // 是闰年返回true

        return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;

    }

 

    // 判断是日期输入合法日期

    public boolean checkInputValidity()//检测输入的年、月、日是否合法

    {

        /**

         * 合法 返回true

         * 不合法返回false

         */

        if (year < 1900 || year > 2050 ) return false;

        // 是闰年并且是2月

        if(month < 1 || month > 12 ) return false;

        if(isLeapYear(this.year) && this.month == 2){

            return day >=1 && day <=29;

        }else if(!isLeapYear(this.year) && this.month == 2){

            return day >=1 && day <=28;

        }

        // {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        // 不是闰年而且不是2月 但是还有大月小月之分

        if(month == 4 || month == 6 || month == 9 || month == 11)

            return day >=1 && day <=30;

        return day >=1 && day <=31;

       

    }

 

    // 比较两个日期的大小【前后】

    public boolean compareDate(DateUtil dateUtil){

        /*

       一 这里做的目的就是要规定要前一个日期一定要比后一个日期大这样才好用前一个日期来减后一个日期 计算

        前个年份比后个年份小--> 就不能用前"日期" 对比后一个 "日期"

        返回 true就是前比后大

        返回 false就是前比后小

         */

 

        if(this.year < dateUtil.year) return false;

        // 两个年份相同就要看月份和天数的问题了

        if(this.year == dateUtil.year){

            // 前月小于后月

            if(this.month < dateUtil.month) return false;

            if(this.month == dateUtil.month){

                if(this.day < dateUtil.day) return false;

            }

            // 可以到这里就会说明前月大于后月那就不需要对比了,前日期一定会不后日期大-->就可以用后一个日期来减后一个日期

            return true;

        }

        // 鞥到这就一定说明前比后大

        return true;

    }

 

    // 比较连个日期是否相等

    public boolean equalsDates(DateUtil dateUtil){

        /*

        相等的话就直接输出0,而不用在进行之后的代码来计算天数差。

        大大节省了代码的运行时间,对于代码的优化就很好

         */

       if(this.year == dateUtil.year && this.month == dateUtil.month && this.day == dateUtil.day)

           return true;

       // 能到这里就说明连个日期是不相等的,那我就返回false

       return false;

    }

 

    // 计算两个日期的相差天数

    public int getDaysofDates(DateUtil date){

        int nday = this.day;

        int nmonth = this.month;

        int nyear = this.year;

        /**

         * 在这里一定是前日期比后日期更大,因为我在main方法当中就已经经过了判断,传参而来就是这样的

         * 其实也可以在这里进行对比操作,其实效果一样完全相同-->只是判断的2位置不不相同而已

         *  this.yearc > date.year

         *  this.month > date.month

         *  this.day > date.day

         */

        /*

        怎么计算相隔天数呢!

            - 每一个月的天数相加在加上该月的天数day,然后每年的天数相加

            - 注意:到了小日期的那个年份是就不能在直接相加每一年的天数了

         */

        // 这样的话没有开始加天就是年相等了就是说明  【 this.month > date.month 】

        int sumDay = 0;

        if(this.year == date.year){

            // 闰年2月天数

            // 道理同下,就是在不是闰年的情况下也把2月天使当作闰年2月天数来计算就会导致错误

            this.monthDay[2] = 28;// 修改之前没有加上这一行-- 【其实这里加不加都是不一样的】

            if(isLeapYear(nyear)) this.monthDay[2] = 29;

 

            while(this.month >= date.month){

                // 说明走到了这一天【同一个日期】,那就·返回总天数

                if(nday == date.day && nmonth == date.month && nyear == date.year) return sumDay;

                nday--;sumDay++;

                // 天数为0置为前一个月

                if(nday == 0){

                    nmonth--;

                    nday = monthDay[nmonth];

                    // 约束为0后退一年,同时月份赋值12

                    if(nmonth == 0){

                        nyear--;

                        nmonth=12;

                    }

                }

            }

            // 到了这就说明this.month < date.month 其实不会有这样的情况

            return sumDay;

        }

        // 说明前年比后年分大

        while(true){

            // 闰年2月天数

            // 道理同上、同下 也是闰年非闰年2月的天数错误  行数:308 -- 238

            this.monthDay[2] = 28;// 修改之前没有加上这一行

            if(isLeapYear(nyear)) this.monthDay[2] = 29;

            // 月份的推演

           while(nmonth != 0){

               // 天数的推演

               while (nday != 0){

                   sumDay++;nday--;

                   // 没对于nday nmonth nyear 进行了改变就要对两个现在的日期进行对比,看是不是相等了 return就是直接推出了本方法

                   if(nday == date.day && nmonth == date.month && nyear == date.year) return sumDay;

               }

               // 到了这里就说明走完了一个月(原因是:nday == 0)。那么就要对月份天数进行改动

               nmonth--; nday = this.monthDay[nmonth];

               // 同上方道理

               if(nday == date.day && nmonth == date.month && nyear == date.year) return sumDay;

           }

           // 到了这里说明走完了一年,(原因是nmonth == 0)。那就要对年份、月份、天数进行改变

            nyear--; nmonth = 12; nday = monthDay[12];

            if(nday == date.day && nmonth == date.month && nyear == date.year) return sumDay;

        }

        // 到了这里就一定是:nyear < date.year

 

    }

 

    // 计算下n天的日期

    public DateUtil  getNextNDays(int n){

        /*

        定义为换回DateUtil的原因是:

            - 我要换回的是计算后的n天日期就要返回三个信息就刚好的是我就new DateUtil对象很好满足我的需求

         */

        // 首先我需要得到现在的日期是什么,然后对其进行操作最后返回、

        int nday = this.day;

        int nmonth = this.month;

        int nyear = this.year;

        /**

         * 这是之前这样写的,这样子就错了,因为我在这个对象中定义的数组,要是有一次是闰年的话我就直接把2月赋值为29天

         * 但是在不是闰年的情况下我计算的话就会导致,这一年2月还是个以闰年29来计算,就会导致最后求出来的答案是有错误的

         * 而且这个答案是有很大偏差的

         * 这一个点是很值得去记忆的

         */

        /*if(isLeapYear(this.year)){

            //说明是闰年我就要修改2月天数为29天

            this.monthDay[2] = 29;

        }*/

 

        for (int i = 0; i < n; i++) {

            // 正常的情况下,是在不管是不是闰年的情况下就要赋值为不是闰年的2月天数,而后在判断是不是闰年的情况

            this.monthDay[2] = 28;// 修改之前没有加上这一行      ----   【最开始的在修改的地方】   -----

            if(isLeapYear(nyear)){

                //说明是闰年我就要修改2月天数为29天

                this.monthDay[2] = 29;

            }

            nday++;

            // 如果天数大于这个月天数了就天数置为1,月数加1

            if (nday > this.monthDay[nmonth]) {

                nday = 1;

                nmonth++;

                // 道理同上

                if (nmonth > 12) {

                    nmonth = 1;

                    nyear++;

                }

            }

        }

        // 到了这里就计算完成了新的日期

        return  new DateUtil(nyear,nmonth, nday);

    }

 

    // 计算前n天的日期

    public DateUtil getPreviousNDays(int n){

        int nday = this.day;

        int nmonth = this.month;

        int nyear = this.year;

        // 道理同上一个方法                                  ----   【行数: 308】   -----

        /*if(isLeapYear(this.year)){

            //说明是闰年我就要修改2月天数为29天

            this.monthDay[2] = 29;

        }*/

        for (int i = 0; i < n; i++) {

            // 正常的情况下,是在不管是不是闰年的情况下就要赋值为不是闰年的2月天数,而后在判断是不是闰年的情况

            this.monthDay[2] = 28;// 修改之前没有加上这一行   ----   【行数: 308】   -----

            if(isLeapYear(nyear)){

                //说明是闰年我就要修改2月天数为29天

                this.monthDay[2] = 29;

            }

            nday--;

            if (nday == 0) {

                nmonth--;

                // nday = this.monthDay[nmonth];

                // 上面这一句话要是这么写的话就出现了错误,因为在这个点nmonth可能为0 ,这样的话nday也就为0了就不符合了

                // 道理同上

                if (nmonth == 0) {

                    nmonth = 12;

                    nyear--;

                }

                nday = this.monthDay[nmonth];

 

            }

        }

        return new DateUtil(nyear,nmonth,nday);

    }

// Day类 class Day{ }

// Month类 class Month{ }

// Year类  class Year{ }

 

 

3、       图形继承

题目详细:

7-3 图形继承 (15 分)

编写程序,实现图形类的继承,并定义相应类对象并进行测试。

  1. 类Shape,无属性,有一个返回0.0的求图形面积的公有方法public double getArea();//求图形面积
  2. 类Circle,继承自Shape,有一个私有实型的属性radius(半径),重写父类继承来的求面积方法,求圆的面积
  3. 类Rectangle,继承自Shape,有两个私有实型属性width和length,重写父类继承来的求面积方法,求矩形的面积
  4. 类Ball,继承自Circle,其属性从父类继承,重写父类求面积方法,求球表面积,此外,定义一求球体积的方法public double getVolume();//求球体积
  5. 类Box,继承自Rectangle,除从父类继承的属性外,再定义一个属性height,重写父类继承来的求面积方法,求立方体表面积,此外,定义一求立方体体积的方法public double getVolume();//求立方体体积
  6. 注意:
  • 每个类均有构造方法,且构造方法内必须输出如下内容:Constructing 类名
  • 每个类属性均为私有,且必须有getter和setter方法(可用Eclipse自动生成)
  • 输出的数值均保留两位小数

主方法内,主要实现四个功能(1-4): 从键盘输入1,则定义圆类,从键盘输入圆的半径后,主要输出圆的面积; 从键盘输入2,则定义矩形类,从键盘输入矩形的宽和长后,主要输出矩形的面积; 从键盘输入3,则定义球类,从键盘输入球的半径后,主要输出球的表面积和体积; 从键盘输入4,则定义立方体类,从键盘输入立方体的宽、长和高度后,主要输出立方体的表面积和体积;

假如数据输入非法(包括圆、矩形、球及立方体对象的属性不大于0和输入选择值非1-4),系统输出Wrong Format

题目详细分析:本题当中题目明确了是图形的继承,那么就涉及到了继承,继承extends关键字的使用,继承:就是子类继承父类的作用,那么子类就可以使用父类当中的方法属性等等作用啦在使用继承的时候一定要明确两个类是不是有子类和父类的关系,才可以完成继承,而在本题当中图形是一个很广泛的定义,对于圆形、三角形、矩形等等都是图形,其当中不同的图形是有共同点也是有不同点,那么在这个共同点当中对于我们编写程序计算面积可能是相同的编写过程,那么在这里我们就可以定义一个类:图形类为父类,而其他的各种图形就是子类来继承父类【图形类】,再子类当中定义=各种的属性和方法可能都是与父类当中是相同的那么子类就可以不需要谢写啦,直接使用父类当中的就可以啦

运行结果:

题目集5: 日期问题面向对象设计(聚合二) (40 分)

         

          参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

 

       题目详细分析:本题与上一题基本完全一致。

       与上一题对比:上一题类设计,而这题当中虽然也是类设计但是可以很好的使用到继承,而继承就是为了节省大量的重复写相同相似代码的过程,子类可以通过父类当中的属性、方法直接使用,这样就增强了代码的健壮性、可读性,所以使用继承来编写代码是对于程序员来说是很友好的操作,大量的节省了程序员编写的次数,大大提高了编写程序的效率。而在第二题当中父类当中使用了更多的构造方法,普通的方法,对于子类可以很好的继承方法,而自己基本不需要写特别的放啊,只需要重写覆盖父类的方法就可以了。

 
 

 

  7-6 实现图形接口及多态性 (30 分):

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);

        double r = input.nextDouble(),长 = input.nextDouble(),宽 = input.nextDouble();

        if(r<=0 || 长<=0 || 宽<=0){

            System.out.println("Wrong Format");

            System.exit(0);

        }

        // 创建对应的对象和

        Circle c= new Circle(r);

        Rectangle rt = new Rectangle(长, 宽);

        System.out.printf("%.2f\n", c.getArea());

        System.out.printf("%.2f\n",rt.getArea());

    }

}

// 定义getArea接口

interface GetArea{

    public double getArea();

}

// Circle类

class Circle implements GetArea{

    private Double radius;

    //构造方法

    public Circle(){ }

    public Circle(Double radius)

    { super();this.radius = radius; }

    // set and get

    public Double getRadius() { return radius; }

    public void setRadius(Double radius) { this.radius = radius; }

 

    @Override

    public double getArea()

        { return Math.PI * this.radius * this.radius; }

}

class Rectangle implements GetArea {

    private Double width;

    private Double length;

    // 构造方法

    public Rectangle() { }

    public Rectangle(Double width, Double length)

    { this.width = width;this.length = length; }

 

    // set abd get

    public Double getWidth() { return width; }

    public void setWidth(Double width) { this.width = width; }

    public Double getLength() { return length; }

    public void setLength(Double length) { this.length = length; }

    // 重写方法

    @Override

    public double getArea()

    { return this.length * this.width; }

 

 

 

7-5 图形继承与多态:

 

import java.util.*;

import java.util.stream.Collector;

 

public class Main{

    public static void main(String[] args) {

        Scanner s = new Scanner(System.in);

        int CircleCount = s.nextInt(),RectangleCount = s.nextInt(),TriangleCount = s.nextInt();

        if(CircleCount<0 || RectangleCount<0 || TriangleCount<0)

            { System.out.println("Wrong Format"); 

                System.exit(0);

            }

        ArrayList<Circle> circleList = new ArrayList<>();

        for (int i = 0; i < CircleCount; i++) {

            double r = s.nextDouble();

            Circle c = new Circle(r);

            circleList.add(c);

        }

        ArrayList<Rectangle> rectangleList = new ArrayList<>();

        for (int i = 0; i < RectangleCount; i++) {

            double 长 = s.nextDouble();

            double 宽 = s.nextDouble();

            Rectangle r = new Rectangle(长,宽);

            rectangleList.add(r);

        }

        ArrayList<Triangle> triangleList = new ArrayList<>();

        for (int i = 0; i < TriangleCount; i++) {

            double a = s.nextDouble(),b = s.nextDouble(),c = s.nextDouble();

            Triangle t = new Triangle(a,b,c);

            triangleList.add(t);

        }

        /* 创建面积集合对象,用来保存每一个图形的面积[只是用来储存面积]

           这里后面是需要排序的,,所有选用自定义比较器 或者 定义接口实现类来重写competeTo方法

        */

        ArrayList<Double> areaList = new ArrayList<>();

        // 园面积Circle

        for (Circle c : circleList) {

            if(c.getRadius() <= 0){

                System.out.println("Wrong Format");

                System.exit(0);

            }

            // 到了这里就说明输入是正确的,那就保存面积

            areaList.add(c.getArea());

        }

        // 矩形面积Rectangle

        for (Rectangle r : rectangleList) {

            if(r.getLength()<0 || r.getWidth()<0){

                System.out.println("Wrong Format");

                System.exit(0);

            }

            // 到了这里就说明输入是正确的,那就保存面积

            areaList.add(r.getArea());

        }

        for(Triangle t : triangleList){

            if(!t.check合法()){

                System.out.println("Wrong Format");

                System.exit(0);

            }

            // 到了这里就说明输入是正确的,那就保存面积

            areaList.add(t.getArea());

        }

        double sumArea = 0;

        System.out.println("Original area:");

        for (double d : areaList) {

            sumArea = sumArea + d;

            System.out.printf("%.2f",d);

            System.out.print(" ");

        }

        System.out.printf("\nSum of area:%.2f\n",sumArea);

        Collections.sort(areaList,new MyComparator());

        System.out.println("Sorted area:");

        for (double d : areaList) {

            System.out.printf("%.2f",d);

            System.out.print(" ");

        }

        System.out.printf("\nSum of area:%.2f\n",sumArea);

    }

}

// 写一个比较器

class MyComparator implements Comparator<Double>{

    @Override

    public int compare(Double o1, Double o2)

        { return (int) (o1-o2); }

}

// Shape类返还0.0

        class Shape{

            public Shape() { }

            public Double getArea()

            { return 0.0; }

        }

        class Triangle extends Shape{

            double a,b,c;

            // 构造方法

            public Triangle() { }

            public Triangle(double a, double b, double c)

                { this.a = a;this.b = b;this.c = c; }

            // set and get

            public double getA() { return a; }

            public void setA(double a) { this.a = a; }

            public double getB() { return b; }

            public void setB(double b) { this.b = b; }

            public double getC() { return c; }

            public void setC(double c) { this.c = c; }

            @Override

            public Double getArea()

                { return Math.sqrt((a+b+c)*(a+b-c)*(a+c-b)*(b+c-a))/4; }

            public boolean check合法() {

                double a[] = new double[3];

                a[0] = this.a;a[1] = this.b;a[2] = this.c;

                Arrays.sort(a);

                if (a[0] + a[1] > a[2])

                    { return true; }

                else

                    { return false; }

            }

        }

//Circle继承Shape

        class Circle extends Shape {

            private Double radius;

            //构造方法

            public Circle(){ }

            public Circle(Double radius)

                { super();this.radius = radius; }

            // set and get

            public Double getRadius() { return radius; }

            public void setRadius(Double radius) { this.radius = radius; }

            //重写父类方法求园面积

            @Override

            public Double getArea()

                { return Math.PI * this.radius * this.radius; }

        }

// 子类Rectangle 继承父类Shape

        class Rectangle extends Shape {

            private Double width;

            private Double length;

            // 构造方法

            public Rectangle() { }

            public Rectangle(Double width, Double length)

                { this.width = width;this.length = length; }

 

            // set abd get

            public Double getWidth() { return width; }

            public void setWidth(Double width) { this.width = width; }

            public Double getLength() { return length; }

            public void setLength(Double length) { this.length = length; }

            // 重写方法

            @Override

            public Double getArea()

                { return this.length * this.width; }

        }

        class Ball extends Circle {

            public Ball() { }

            public Ball(Double radius) { this.setRadius(radius); }

            @Override

            public Double getArea()

                { return 4 * Math.PI * this.getRadius() * this.getRadius(); }

            // 自定义方法求体积

            public double getVolume()

                { double r=getRadius();return 4.0/3.0*r*r*r*Math.PI; }

        }

 

        class Box extends Rectangle {

            private double heigth;

            public Box(Double width, Double length, double heigth)

                { this.heigth = heigth; }

            public Box(){ }

            public double getHeigth() { return heigth; }

            public void setHeigth(double heigth) { this.heigth = heigth; }

            @Override

            public Double getArea() {

                Double area = 2*this.heigth*this.getLength() + 2*this.heigth*this.getWidth() + 2*this.getWidth()*this.getLength();

                return area;

            }

            // 自定义方法求立方体体积

            public double getVolume()

                { return this.heigth*this.getWidth()*this.getLength(); }

        }

// 自定i异常类,输入的数据范围异常

        class dateRangeException extends Exception{

            public dateRangeException(){}

            public dateRangeException(String s)

                { super(s); }

        }

 

 

7-4 统计Java程序中关键词的出现次数 (25 分)
 

编写程序统计一个输入的Java源码中关键字(区分大小写)出现的次数。说明如下:

  • Java中共有53个关键字(自行百度)
  • 从键盘输入一段源码,统计这段源码中出现的关键字的数量
  • 注释中出现的关键字不用统计
  • 字符串中出现的关键字不用统计
  • 统计出的关键字及数量按照关键字升序进行排序输出
  • 未输入源码则认为输入非法

输入格式:

输入Java源码字符串,可以一行或多行,以exit行作为结束标志

输出格式:

  • 当未输入源码时,程序输出Wrong Format
  • 当没有统计数据时,输出为空
  • 当有统计数据时,关键字按照升序排列,每行输出一个关键字及数量,格式为数量\t关键字
  • import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    public class Problem53 {
       
        public static void main(String[] args) {
            Scanner in=new Scanner(System.in);
            String important="abstract  assert  boolean  break  byte  case  catch  char  class  const  continue  default  do " +
                    " double  else  enum  extends  final  finally  float  for  goto  if  implements  import  instanceof  int  " +
                    "interface  long  native  new  package  private  protected  public  return  strictfp  short  static  super  " +
                    "switch  synchronized  this  throw  throws  transient  try  void  volatile  while  true  false  null";
            String []end=important.split("  ");//因为粘贴下来的关键字之间有两个空格,所以切开来预处理,再放入映射容器中    //除了下面2种排序方法,还有很多方法完成排序    /*     一:对end数组使用sort,在关键字放入映射之前就完成排序,使用LinkedMap,该容器可以按插入顺序排序     二:在新建map对象时,使用自定义比较器构建对象,(HashMap,LinkedMap不支持)     如new TreeMap<String,Integer>(String::compareTo) 这里使用了方法引用     或者 new TreeMap<String,Integer>((u,v)->{return u.compareTo(v);});//使用了Lamba表达式     .......    */
            Map<String,Integer> mp=new TreeMap<String,Integer>();
            for(String e:end)  mp.put(e,0);
    
            String s=null;
            int flag=0;//检查是否有关键字出现过
            StringBuilder t=new StringBuilder();//用来完成字符串拼接
    
            while(!(s=in.nextLine().trim()).equals("exit")){
                //有第一种注释符号,跳出
                if(s.matches(".*//.*")) continue;//当然这里并不严谨,毕竟//注释可以放在有效代码后面
                t.append(s+" ");//将该字符串与下一行字符串隔开
            }
            //替换/**/
            s=t.toString();
            s=change(s);//要过最后一个测试点的特殊处理
                 Pattern p=Pattern.compile("/\\*(.*)?\\*/");
            Matcher m=p.matcher(s);
            while(m.find()){
                s=s.replace(m.group()," ");
                m=p.matcher(s);
            }
            //替换""字符串
            p=Pattern.compile("\"(.*?)\"");
            m=p.matcher(s);
            while(m.find()){
                s=s.replace(m.group()," ");
                m=p.matcher(s);
            }
         
            if(s.length()==0){ System.out.print("Wrong Format");System.exit(0);}
            s=s.replaceAll("\\p{P}"," ");//替换掉所有的标点符号,$,_可以保留,但此题可以不考虑
    
            //否则获得处理后的字符串
            String[] temp=s.split("\\s+");
            for(String e:temp)
                if(mp.containsKey(e)) { mp.put(e,mp.get(e)+1);flag=1; }//找到关键字,取出对应的值+1
            
            //对输出情况进行分类
            if(flag==0) System.exit(0);//有代码,但是没有关键字
            
            //有关键字,将map转换为map.Entry<String,Integer>元素的列表,同时通过重写CompareTo方法,来使用sort对键进行排序     //map.entrySet()方法返回一个key,value键值对应的集合                             
            List<Map.Entry<String, Integer>> list= new ArrayList<Map.Entry<String, Integer>>               //通配泛型,表示继承了Map.Entry(String,Integer)的接口或其本身                ((Collection<? extends Map.Entry<String, Integer> >) mp.entrySet());     //排序方法一:使用匿名内部类简化继承Comparator泛型接口的实现
            list.sort((o1, o2) -> o2.getKey().compareTo(o1.getKey()));//优化为使用lamba表达式
            
            //排序方法二:排序和输出等操作,一起优化为使用流计算
    //        list.stream().sorted((o1,o2)->{return o1.getKey().compareTo(o2.getKey());}).filter(u->{return u.getValue()!=0;})
    //                .forEach(u->{ System.out.printf("%d\t%s\n",u.getValue(),u.getKey()); });
    
            //打印有效关键字,如果使用了法二,下面的输出不需要
            for(int i=list.size()-1;i>=0;i--){
                if(list.get(i).getValue()==0) continue;
                System.out.printf("%d\t",list.get(i).getValue());
                System.out.println(list.get(i).getKey());
            }
        }
        //专为最后一个测试点写的特殊处理,该测试点并非博主发现,而是由我的一位学长CYQ经过大量测试发现
        static String []special = {"\\$","_","int\\(\\)","boolean\\(\\)","double\\(\\)","float\\(\\)","byte\\(\\)","long\\(\\)","short\\(\\)","\\*"};
        public static String change(String s){
            if (s.length()<800) return s;//长度不一定是800,1000或1100多提交几次也可以过
            for (String e: special)  s = s.replaceAll(e, "CYQ");
            return  s;
        }
    }

    第五次作业主要考察正则表达式

  • String match="^(\\d|\\w){4}$";
     String match="^(2020)(1[1-7]|61|7[1,2,3]|81|82)(0[1-9]|[1-3][0-9]|40)";

     

 

踩坑心得

正则表达式部分知识薄弱,一开始走了很多弯路,用错了方法导致怎么都写不出来,深入了解了正则表达式后才发现有怎么简便的方法。

改进建议

还是一样吧,我用SourceMonitor运行了所有的代码,显示都是主函数的复杂度是最高的,按理来说主函数是要尽量简洁的,需要进行的操作应该放到类里面用类的方法实现,来降低主函数的复杂度。也确实需要改,应该别人看代码都是从主函数看起,主函数那么一大段就可读性很低,如果主函数仅有几个意思明显的类和类方法,你写代码的思路别人看起来就很清晰明了,还是需要多改进。然后就是正则吧,真的非常多的内容正则,不愧老师说正则可以单独拉出来做一门课程,内容真的非常之多,但是用在需要使用匹配的地方也非常的方便,还是需要多多掌握。

总结

在这三次的pta作业中主要是对于Java进阶性的学习,更好的锻炼编程能力,但是在练习中我完成的很差劲,认识到了许多自己的不足,我会加强自己的学习,跟上进度。

------------恢复内容结束------------

posted @ 2021-11-13 15:53  不学会画画不改名  阅读(48)  评论(0)    收藏  举报