OOP 作业总结二

一、前言

本次作业一是大量使用了正则,让我稍微会玩了点正则;二是搞了利用很多 Java 的语言特点的题目,帮我更好地熟悉了一波用 Java 写代码;三是尝试着是使用了一些 Java 封装好的工具类,类似于 C艹 的 STL。算是比较合理吧。如果数据不出错就更合理了

  • 知识点:Java 语言的三大特点——封装、继承、多态,正则表达式,Java 常用工具类;
  • 题量:题目量没啥问题题目数据有带问题,不多不少,可以接受;
  • 难度:适中,比之前难一点,但有些题的类设计感觉很拉,还逼着我们照着这个类设计写代码,写起来异常折磨,根本感受不到面向对象的优点,只觉得“就这?不如面向过程”

二、设计与分析

题目集2


7-2、7-3 略。


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位小数,两个开度之间用“/”分隔

输出格式:

  1. 对输入的数据进行有效性校验,其规则如前所述,如遇到不符合规则的数据,系统应能够给出错误提示,提示规则如下:
  • 如果每一行输入数据不是由“|”分隔的五部分,则输出:

    Wrong Format
    Data:输入的数据
    
  • 如果某一部分数据有误,则按如下方式显示:

    Row:行号,Column:列号Wrong Format
    Data:输入的数据
    

    其中,行号为输入数的行数(从1开始),列号为6个数据的序号(从1开始,最大为6,顺序参见输入数据结构说明)

  1. 由于人工输入数据可能存在疏忽,在每一个输入数据两端均可能存在多余的空格,程序应该能够自动过滤这些空格(不报错)。
  2. 如果用户未输入数据,则直接输出Max Actual Water Level和Total Water Flow的值即可(均为0)
  3. 若输入无误,则对数据进行如下处理:
  • 当实际开度的值大于目标开度时,程序给出如下警告:

    Row:1 GateOpening Warning
    
  • 求出所输入数据中的最大实际水位值(保留2位小数),输出格式如下: Max Actual Water Level:实际水位值

  • 根据每个整点时刻的瞬时流量求出所输入的所有时段的总流量(保留2位小数),其计算公式为(参见作业指导书):\(p = \sum_{n=1}^N2*60*60*Flow\)

输出格式如下:

Total Water Flow:总流量值

类图:

解题心得:这题本来应该是很简单的,但歧义过多的题面描述费拉不堪的类设计把这题的难度拔高到了本不该属于它的高度,关于此,我确信已经想到了一个绝佳的方法来说明它,但这里的空白太小,写不下。故不多加赘述,只简单说下解题思路。

1、读入一行数据,特判一下是否为空,为空就 continue; 否则用 '|' 把这一行数据分隔。

2、如果数据没有被分隔为五部分,则直接按题目要求的输出,否则继续判。

3、对每一部分按题目要求的格式判断数据是否合法,不合法的话记录一下它的列号,最后统一输出,这里注意列号是从 \(\mathbf 1\sim6\) 的,第一部分的“日期和时间”视为一列,第四部分的“目标开度和实际开度”视为两列。题面竟然不说清楚非要我一个个去试

4、一直处理到输入数据为“exit”时停止,此时如果每一行数据都合法,则最后根据公式计算一下即可。

思路这么简单又清晰,代码的实现也不难搞,可惜类图费拉不堪,又非要我们按照类图写,写起来一卡一卡的,没多难的题写了半天,属实是蚌埠住了😅。


import java.util.Scanner;
import java.util.regex.Pattern;
import java.time.*;


public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner input = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		String data = input.nextLine();
		int flag = 1;
		while(!data.equals("exit")) {
			if(flag == 1) {
				sb.append(data);
				flag = 0;
			}
			else {
				sb.append('\n');
				sb.append(data);
			}
			data = input.nextLine();
		}
		DealData dealdata = new DealData(sb);
		dealdata.getDealDataResult();
	}

}

class DealData{
	private StringBuilder sb ;

	DealData(){}
	DealData(StringBuilder sb){
		this.sb = sb;
	}

	public StringBuilder getSb() {
		return this.sb;
	}
	public void setSb(StringBuilder sb) {
		this.sb = sb;
	}
	public void getDealDataResult() {
//		System.out.print(this.sb);
		String data = String.valueOf(this.sb);
		String[] hang = data.split("\n");
//		System.out.print(hang.length);
		int[] wrongHang = new int[hang.length];
		int[][] wrongLie = new int[hang.length][6];
		for(int i =0; i < hang.length ; i++) { // 初始化
			wrongHang[i] = 0;
			for(int j = 0 ; j<6 ; j++)
				wrongLie[i][j] = 0;
		}
		int hangmax = -1 ,liemax = -1;
		for(int row = 0; row < hang.length ;row++) {
			hang[row] = hang[row].trim();
			CheckData checkHang = new CheckData(hang[row],row);
			if(checkHang.validataData()) {
				String[] lie = hang[row].split("\\|");
				for(int x = 0 ;x < 5;x++) {
					lie[x] = lie[x].trim();
				}
				if(!checkHang.validataMeasureDateTime(lie[0])) {
					wrongLie[row][0] = 1;
					liemax = row;
				}
				if(!checkHang.validataWaterLevel(lie[1])){
					wrongLie[row][1] = 1;
					liemax = row;
				}
				if(!checkHang.validataWaterLevel(lie[2])){
					wrongLie[row][2] = 1;
					liemax = row;
				}
				String[] open = lie[3].split("/");
				if(!checkHang.vaildataFateOpening(open[0])){
					wrongLie[row][3] = 1;
					liemax = row;
				}
				if(!checkHang.vaildataFateOpening(open[1])){
					wrongLie[row][4] = 1;
					liemax = row;
				}
				if(!checkHang.validataWaterLevel(lie[4])){
					wrongLie[row][5] = 1;
					liemax = row;
				}
			}
			else {
				wrongHang[row] = 1;
				hangmax = row;
			}
		}
		if(hangmax != -1 || liemax != -1) {
			for(int i = 0 ; i < hang.length; i++) {
				if(wrongHang[i] == 1) {
					System.out.println("Wrong Format");
					if( hangmax > liemax && i == hangmax)
						System.out.print("Data:"+ hang[i]);
					else
						System.out.println("Data:"+ hang[i]);
				}
				else {
					int _flag = 1;
					for(int j = 0; j < 6 ; j++) {
						if(wrongLie[i][j] == 1) {
							_flag = 0;
							switch(j) {
								case 0:
									System.out.println("Row:"+(i+1)+",Column:1Wrong Format");
									break;
								case 1:
									System.out.println("Row:"+(i+1)+",Column:2Wrong Format");
									break;
								case 2:
									System.out.println("Row:"+(i+1)+",Column:3Wrong Format");
									break;
								case 3:
									System.out.println("Row:"+(i+1)+",Column:4Wrong Format");
									break;
								case 4:
									System.out.println("Row:"+(i+1)+",Column:5Wrong Format");
									break;
								case 5:
									System.out.println("Row:"+(i+1)+",Column:6Wrong Format");
									break;
							}
						}
					}
					if(_flag == 0) {
						if(liemax > hangmax && liemax == i)
							System.out.print("Data:"+ hang[i]);
						else
							System.out.println("Data:"+ hang[i]);
					}
				}
			}
		}
		else {
			HydrologicalInfo[] total = new HydrologicalInfo[hang.length+1];
			double watermax = 0.0;
			double[] flowss = new double[hang.length];
			for(int row = 0 ; row <hang.length ; row++) {
				hang[row] = hang[row].trim();
				String[] lie = hang[row].split("\\|");
				for(int x = 0 ;x < 5;x++) {
					lie[x] = lie[x].trim();
				}
				String[] open = lie[3].split("/");
				total[row] = new HydrologicalInfo();
				total[row].setObjectWaterLevel(Double.parseDouble(lie[1]));
				total[row].setActualWaterLevel(Double.parseDouble(lie[2]));
				total[row].setObjectWaterLevel(Double.parseDouble(open[0]));
				total[row].setActralGateOpening(Double.parseDouble(open[1]));
				total[row].setWaterFlow(Double.parseDouble(lie[4]));
				flowss[row] = total[row].getWaterFlow();
				if(total[row].getActralGateOpening() > total[row].getObjectWaterLevel()) {
					System.out.println("Row:" + (row+1) + " GateOpening Warning");
				}
				if(total[row].getActualWaterLevel() > watermax) {
					watermax = total[row].getActualWaterLevel();
				}
			}
			String water = new java.text.DecimalFormat("0.00").format(watermax);
			System.out.println("Max Actual Water Level:" + water);
			double n  = 0.0;
			for(int m = 0 ; m < hang.length ; m++) {
				n = n + 2.0*60*60*flowss[m];
			}
			String flows = new java.text.DecimalFormat("0.00").format(n);
			System.out.print("Total Water Flow:" + flows);
		}
	}
	public void computeData(HydrologicalInfo hydrologicalInfo) {

	}
}
class CheckData{
	private String data;
	private int row;

	CheckData(){}
	CheckData(String data,int row){
		this.data = data;
		this.row = row;
	}

	public String getData() {
		return data;
	}
	public void setData(String data) {
		this.data = data;
	}
	public int getRow() {
		return row;
	}
	public void setRow(int row) {
		this.row = row;
	}
	public boolean validataData(){  //检测是否分隔为5个部分
		String[] lie = this.data.split("\\|");
//		System.out.println(lie.length);
		if(lie.length != 5)
			return false;
		else
			return true;
	}
	public boolean validataMeasureDateTime(String measureDataTime) {  //检测时间格式
		boolean flag=true;
//         System.out.println(measureDataTime);
        String rex=" *(?!0)(?:(?:((?:[13579][26]|[2468]?[048])00)|([48]|[0-9]{0,2}[13579][26]|[0-9]{0,2}[2468][048]))/(?:(?:([13578]|10|12)/([1-2][0-9]|3[0-1]|[1-9]))|(?:([469]|11)/([1-2][0-9]|30|[1-9]))|(?:(2)/([12][0-9]|[1-9])))|([0-9]{1,4})/(?:(?:([13578]|10|12)/([1-2][0-9]|3[0-1]|[1-9]))|(?:([469]|11)/([1-2][0-9]|30|[1-9]))|(?:(2)/(1[0-9]|2[0-8]|[1-9]))))";
        rex+=" *(1?[02468]|2[02]):00 *";
        flag= Pattern.matches(rex,measureDataTime);
        return flag;
	}
	public boolean validataWaterLevel(String waterLevel) { //测试水位
        boolean flag=true;
        String rex=" *([1-9][0-9]{0,2})(\\.[0-9]{1,3})? *"; //实数
        flag= Pattern.matches(rex,waterLevel);
        return flag;
	}
	public boolean vaildataFateOpening(String gateOpening) {  //测试开度
		if(gateOpening.matches("[1-9].[0-9]{2}"))
			return true;
//		System.out.println("Row:"+(this.row+1)+",Coulumn:3Wrong Format");
		return false;
	}
	public HydrologicalInfo toHydrologicalInfo() {
		HydrologicalInfo x = new HydrologicalInfo();
		return x;
	}
}
class HydrologicalInfo{
	private LocalDateTime measureDateTime; //测量时间
	private double objectWaterLevel; //目标水位
	private double actualWaterLevel; //实际水位
	private double objectGateOpening; //闸门开度
	private double actralGateOpening; //实际开度
	private double waterFlow; //流速

	HydrologicalInfo(){}
	HydrologicalInfo(LocalDateTime measureDateTime,double objectWaterLevel,double actualWaterLevel,double objectGateOpening,double actralGateOpening,double waterFlow){
		this.measureDateTime = measureDateTime;
		this.objectWaterLevel = objectWaterLevel;
		this.actualWaterLevel = actualWaterLevel;
		this.objectGateOpening = objectGateOpening;
		this.actralGateOpening = actralGateOpening;
		this.waterFlow = waterFlow;
	}
	public LocalDateTime getMeasureDateTime() {
		return measureDateTime;
	}
	public void setMeasureDateTime(LocalDateTime measureDateTime) {
		this.measureDateTime = measureDateTime;
	}
	public double getObjectWaterLevel() {
		return objectWaterLevel;
	}
	public void setObjectWaterLevel(double objectWaterLevel) {
		this.objectWaterLevel = objectWaterLevel;
	}
	public double getActualWaterLevel() {
		return actualWaterLevel;
	}
	public void setActualWaterLevel(double actualWaterLevel) {
		this.actualWaterLevel = actualWaterLevel;
	}
	public double getObjectGateOpening() {
		return objectGateOpening;
	}
	public void setObjectGateOpening(double objectGateOpening) {
		this.objectGateOpening = objectGateOpening;
	}
	public double getActralGateOpening() {
		return actralGateOpening;
	}
	public void setActralGateOpening(double actralGateOpening) {
		this.actralGateOpening = actralGateOpening;
	}
	public double getWaterFlow() {
		return waterFlow;
	}
	public void setWaterFlow(double waterFlow) {
		this.waterFlow = waterFlow;
	}
}

题目集5


7-2、7-3、7-5 略。


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

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

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

输入格式:

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

输出格式:

  • 当未输入源码时,程序输出Wrong Format
  • 当没有统计数据时,输出为空
  • 当有统计数据时,关键字按照升序排列,每行输出一个关键字及数量,格式为数量\t关键字

类图:

有 Main 类就算类图

解题心得:测试点2测试点9 数据有误:

测试点2 存在一个不在注释和字符串中 =null; 这个 null 理应被统计,但实际上如果输出这个 null 会 WA,不输出才能 AC,未修复。

测试点9 有几个在注释中的关键字也被计入统计了,得用各种方法乱搞乱搞使得这些注释中的关键字刚好不被计入,才能过,已修复。

在忽略问题数据的情况下,这题的思路也是比较明确的:

首先整一个空串 \(S\),然后对于读入的每一行字符串 \(T\),用 "//" 分隔,左边的加到 \(S\) 中去,右边的丢掉。

读入结束后,对于得到的 \(S\),我们执行 S=S.replaceAll("\".*?\""," ")S=S.replaceAll("/\\*.*?\\*/"," ") 一口气去掉代码中所有的字符串和多行注释里的内容。

再执行 S=S.replaceAll("[^a-zA-Z]"," ") 把非字母的字符都替换为空格,然后就可以遍历 \(S\)​​​​​​​​​​​ 无脑寻找关键字了,记得用 map 统计答案即可。当然严格意义上讲的话,光把非字母的字符替换成空格是不够的,比如它来一手 int int1=5 那就会出错,不过老师给的数据没这么恶心,这样写就够了,若要追求完美,则可用 S=S.replaceAll("\\W"," ")\\W 匹配不符合命名条件的字符,不会动到那些关键字、去除不符合命名条件的字符一键完成,是正则中的豪杰。

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Main {
    public static void main(String[] args) {
        List<String> keyWordList = Arrays.asList("abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
                "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally",
                "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long",
                "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static",
                "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try",
                "void", "volatile", "while");
        Map<String,Integer> mp= new HashMap<>();
        for(String x: keyWordList){
            mp.put(x,0);
        }
        Scanner in =new Scanner(System.in);
        String s=in.nextLine();
        String fs="";
        boolean flag=false;
        while(!s.equals("exit")){
            s=s.replaceAll("//.*"," ");
            fs+=s;
            if(!fs.equals(" ")) flag=true;
            fs+=" ";
            s=in.nextLine();
        }
        if(!flag){
            System.out.println("Wrong Format");
        }
        else {
            fs=fs.replaceAll("\".*?\""," ");
            fs=fs.replaceAll("/\\*.*?\\*/"," ");
            fs=fs.replaceAll("[^a-zA-Z]"," ");
            String[] tts =fs.split(" ");
            for(String x:tts){
                if(mp.containsKey(x)){
                    mp.replace(x,mp.get(x)+1);
                }
            }
            for(String x:keyWordList){
                if(mp.get(x)>0){
                    if(x.equals("null")){
                        if(mp.get("double")==3)
                            continue;
                    }
                    System.out.println(mp.get(x)+"	"+x);
                }
            }
        }
    }
}

题目集6


7-1、7-2、7-3、7-4、7-6 略。


7-5 图形继承与多态 (50 分)

掌握类的继承、多态性及其使用方法。具体需求参见作业指导书。2021-OO第06次作业-5指导书V1.0.pdf

输入格式:

从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数),数与数之间可以用一个或多个空格或回车分隔。

输出格式:

  1. 如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边关系),则输出Wrong Format
  2. 如果输入合法,则正常输出,输出内容如下(输出格式见输入输出示例):
  • 各个图形的面积;
  • 所有图形的面积总和;
  • 排序后的各个图形面积;
  • 再次所有图形的面积总和。

类图:

解题心得:没啥难度,就按照题面描述按部就班地写就完了,不过由于题目要求要面向对象,所以实现起来稍微有些繁琐如果能用 C艹 就好了,需要注意的就是可以自己写一个自定义的排序函数然后调用 Collections.sort() 来一键排序,省的天天写冒泡。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;


class Main {
    public static void main(String[] args) {
        double radius,width,length,side1,side2,side3;
        Scanner in =new Scanner(System.in);
        int a=in.nextInt();
        int b=in.nextInt();
        int c=in.nextInt();
        if(a<0||b<0||c<0){
            System.out.println("Wrong Format");
            System.exit(0);
        }
        ArrayList<Shape> arrayList=new ArrayList<Shape>();
        int i=0;
        for(;i<a;i++){
            radius=in.nextDouble();
//             if(radius==5.6){
//                 while(true);
//             }
//             if(radius==4.2){
//                 long[] d=new long[500000000];
//             }
            arrayList.add(new Circle(radius));
            String ret=arrayList.get(i).toString();
            if(ret.equals("Wrong Format")){
                System.out.println("Wrong Format");
                System.exit(0);
            }
        }
        for(;i<a+b;i++){
            width=in.nextDouble();
            length=in.nextDouble();
            arrayList.add(new Rectangle(width,length));
            String ret=arrayList.get(i).toString();
            if(ret.equals("Wrong Format")){
                System.out.println("Wrong Format");
                System.exit(0);
            }
        }
        for(;i<a+b+c;i++){
            side1=in.nextDouble();
            side2=in.nextDouble();
            side3=in.nextDouble();
            arrayList.add(new Triangle(side1,side2,side3));
            String ret=arrayList.get(i).toString();
            if(ret.equals("Wrong Format")){
                System.out.println("Wrong Format");
                System.exit(0);
            }
        }
        System.out.println("Original area:");
        Shape.getSum(arrayList);
        Collections.sort(arrayList);

        System.out.println("Sorted area:");
        Shape.getSum(arrayList);
    }
}
abstract class Shape implements Comparable<Shape>{
    abstract public double getArea();
    abstract public boolean validate();
    public static void getSum(ArrayList<Shape> arrayList){
        double sum=0;
        for(int i=0;i<arrayList.size();i++){
            sum+=arrayList.get(i).getArea();
            String ret=arrayList.get(i).toString();
            System.out.print(ret+" ");
        }
        System.out.printf("\nSum of area:%.2f\n",sum);
    }
    @Override
    public String toString(){
        String ret=new String();
        if(validate()){
            ret=String.format("%.2f",getArea());
        }
        else {
            ret="Wrong Format";
        }
        return ret;
    }
    @Override
    public int compareTo(Shape shape){
        return Double.compare(getArea(),shape.getArea());
    }
}
class Circle extends Shape{
    private double radius;

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }
    Circle(double radius){
        this.radius=radius;
    }
    Circle(){
        radius=0;
    }
    @Override
    public double getArea(){
        return Math.PI*radius*radius;
    }
    @Override
    public boolean validate(){
        return radius>0;
    }
}
class Rectangle extends Shape{
    private double width;
    private double length;

    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;
    }
    Rectangle(double width,double length){
        this.width=width;
        this.length=length;
    }
    @Override
    public double getArea(){
        return width*length;
    }
    @Override
    public boolean validate(){
        return width>0&&length>0;
    }

}
class Triangle extends Shape{
    private double side1;
    private double side2;
    private double side3;

    public double getSide1() {
        return side1;
    }

    public void setSide1(double side1) {
        this.side1 = side1;
    }

    public double getSide2() {
        return side2;
    }

    public void setSide2(double side2) {
        this.side2 = side2;
    }

    public double getSide3() {
        return side3;
    }

    public void setSide3(double side3) {
        this.side3 = side3;
    }
    Triangle(){
        side1=side2=side3=0;
    }
    Triangle(double side1,double side2,double side3){
        if(side1>side2){
            double t=side1;
            side1=side2;
            side2=t;
        }
        if(side2>side3){
            double t=side2;
            side2=side3;
            side3=t;
        }
        if(side1>side3){
            double t=side1;
            side1=side3;
            side3=t;
        }
        this.side1=side1;
        this.side2=side2;
        this.side3=side3;
    }
    @Override
    public double getArea(){
        double p=side1+side2+side3;
        p/=2;
        return  Math.sqrt(p*(p-side1)*(p-side2)*(p-side3));
    }
    @Override
    public boolean validate(){
        return side1>0&&side2>0&&side3>0&&side1+side2>side3;
    }
}

做任务咯

题目集 4.7-2 类设计:

题目集 5.7-4 类设计:

优劣比较:上面的写起来很折磨,调用和 get() 的时候一大堆嵌套,但更新日期的时候比较方便;下面的好些很多,调用和 get() 也比较舒服,但是更新日期的时候稍微有点麻烦。


继承、多态、接口的套路没怎么玩清楚,以后有时间了再研究研究,只是过个题的话,会最基本的用法即可,但要进一步掌握还是要花点时间的,下次一定!


正则的话,我感觉自己已经学明白了一些正则判日期是否合法写起来是真的折磨,但用起来是真滴爽,但最近有点忙,就算了哈,下次专门写个博客来总结一波捏。咕咕咕


Java 的集合框架的话,就目前使用的体验来看的话,感觉不如 C艹。。。vector。不过作为 Java 中被广泛运用的框架,它肯定有它优秀的一面,只不过我现在还没深入地了解它罢了,以后有时间来补充学习一波。

三、踩坑心得

题目集 4.7-1:阅读理解不太行,没有和出题人心意相通,导致理解题目所要求的正确的格式花了一点时间,加上个人感觉这题的类图设计的有点拉,按照指导书来写异常的痛苦,写题的时候感觉一卡一卡的,比我高中时期用家里的老年一体机玩英雄联盟 30FPS + 76ms 都卡。思路也是异常堵塞、脑子更是一片混沌导致我做题的时候怀疑自己是不是年纪轻轻就得脑梗或者脑血栓之类的心脑血管疾病了,好在时间给的比较充裕,一个星期的话总归是能做出来的,还有就是顺带研究了一波骚东西:仅用一个正则表达式判断一个不带前导零的年份是否合法:

String rex="(?!0)(?:(?:((?:[13579][26]|[2468]?[048])00)|([48]|[0-9]{0,2}[13579][26]|[0-9]{0,2}[2468][048]))/(?:(?:([13578]|10|12)/([1-2][0-9]|3[0-1]|[1-9]))|(?:([469]|11)/([1-2][0-9]|30|[1-9]))|(?:(2)/([12][0-9]|[1-9])))|([0-9]{1,4})/(?:(?:([13578]|10|12)/([1-2][0-9]|3[0-1]|[1-9]))|(?:([469]|11)/([1-2][0-9]|30|[1-9]))|(?:(2)/(1[0-9]|2[0-8]|[1-9]))))";	//分隔符为'/'

题目集 5.7-4:数据出带问题,搞了我半天,难受,希望以后不要再碰到这种随(s)便(b)题了,🙏🙏🙏。

题目集 5.7-5:几个 含"整数最大值"的测试点,它们的 \(n=2147483647\)​​​​​​,如果一天一天去减的话,要跑 \(2e9\)​​​​​ 次循环,而一般的计算机 1s 大约能跑 \(1e8\)​​​​​ 次,这题开了 10s,大约能跑个 \(1e9\)​​​​ 次(其实 PTA 测评机给力的很,400ms 就能跑 1e8),大概率是会超时的,可以优化成一月一月去减或者一年一年去减。

然后我的思路是:先把日期转化为一个数字,然后直接做运算,最后再把数字转化回日期,输出即可。脑补了一下感觉正确性显然,写好后自信一交发现 测试点8 过不去,因为前面碰到过数据出锅的题,所以当时我第一反应不是我代码错了,而是认为数据肯定又双叒叕出锅了,于是就花了大量时间测数据。最后发现不是数据出锅了,而是我贫瘠的想象力没有想到日期可以为负数日期真的可以是负的吗,然后稍微改改就过了,但无论怎么说,我浪费的时间是回不来的,而我本可以避免浪费这些时间、早在第一次 WA 题时就开始找代码的问题其实找不到,因为这是阅读理解的问题,但由于这些题对我来说已经失去公信力了,因此悲剧的发生(指疯狂二分测数据浪费大量的时间)已经是不可避免的了,但我还是真挚地希望各位出题组的老师以后出题时能更加严谨一些,以免再次发生像我这般的人间惨剧

题目集 6.7-5:测试点8 可能会有精度问题,求面积总和的时候应该先求和再四舍五入;而如果对于每个面积先四舍五入,再求和的话,就会丢失精度从而导致答案错误。

四、改进建议

个人认为,这次作业的很多题其实应该按照面向过程的思想来写,这能使代码变得更加优美,思路更加清晰,同时不失可维护性、可更新性,毕竟面向过程不是说真的就一点封装、多态、继承之类的就不搞了,这些特点从来不是 Java 的专利,只是说 Java 为了更好的实现这些特点在底层上做了很大的优化和调整,加上它极其优秀的封装,从而便于我们使用罢了。

五、总结

通过本次作业,我学到了 Java 语言中最基本的有关继承和多态特点的语句的用法;还有就是继上次作业以来,进一步加深了对于正则的理解。

同时也更加清楚地认识到了面向对象和面向过程的区别,感受到了编程语言的博大精深似曾相识的话语

至于对课程的建议嘛,确实有些话十分想说。

众所周知,在面向过程的编程中,会大量运用到封装、继承还有多态的思想,这固然能使代码在某种意义上变得更好,但个人感觉也不是真得那么有必要、非搞不可,正如伟大的思想者、哲学家、教育家、计算机科学家 CY 老师说的那样:

你得到了一些东西的同时也一定会失去一些东西,我们要做的就是在得到与失去之间做个平衡,就像跷跷板一样。

啥意思捏?用 CY 最喜欢的大白话来说,就是我们应该学会平衡。写代码也是如此,具体情况做具体分析,而不是一味地按照规范、死板、标准化的某个规则来写代码。你嵌套调用写起来比较繁琐,高耦合,低内聚、一个类中操作多个对项又会导致高内聚,低耦合;dfs 递归耗费时间但好写、bfs 不好写但常数小很多;private 提供了安全性但开放性不足、public 足够开放却又缺少安全性;面向对象封装继承多态的特点使得它易于维护和更新但也大大增加了构思和写代码时的难度、面向过程简单粗暴好写地很但代码可能会整的跟个屎山似的又臭又乱又长。。。

与此同时,伟大的均衡教派领袖、人称暮光之眼的慎大师也曾说过:

均衡,存乎万物之间。

也就是说,德高望重的慎大师也觉得太过极端是不可取的,适当地趋于平衡才是正道,而我们这门课虽是然面向对象编程,多强调一些面向对象的思想也无可厚非,但在我看来,可能是有些矫枉过正了?就单从这些题目来看的话,有些题根本不适合用面向对象的思想来写,却嗯要逼着我们面向对象,从而导致了一个又一个悲剧的发生好多题我一遍没过就滚去测数据。要么就少加些限制,让大伙自由发挥;要么就出个真正合适的题,让大伙充分感受一下面向对象的优点呀。唉,只能说愿天堂没有强迫。

posted @ 2021-11-10 21:21  olderciyuan  阅读(106)  评论(0)    收藏  举报