22206108hzy

导航

有关java的博客

有关java的第四五次大作业与期中考试总结

一、前言

本次博客主是针对java学习第二阶段中的PTA题目与期中考试题目的总结性博客,第二阶段的作业难度与第一阶段想必有所提高,对java的知识点考察主要集中在类的设计,正则表达式的运用,类的继承,多态,抽象类与接口。
期中考试代码情况:

二、设计与分析

1、java期中考试的三四题

完成情况:

这里重点来分析第三题和第四题。

—— 1.1测验3-继承与多态
1)类图:

2)生成报表:

(绿色环形区域即被测量维度的期望值,维度上的点则是测量得到的实际值)

据报表分析:平均圈复杂度和函数深度都比较低,说明代码简洁明了。

3)类设计:

✔️ 继承关系:Shape做抽象形状类,有getarea方法,三角形类和矩形类继承Shape类,并覆盖其getarea方法。

✔️ 组合关系:矩形有四个点,故点类是矩形类为组合关系

4)代码如下:

import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner input = new Scanner(System.in);
        
        int choice = input.nextInt();
        
        switch(choice) {
        case 1://Circle
        	double r=input.nextDouble();
        	Shape circle = new Circle(r);
        	if(r<=0) {
        		System.out.println("Wrong Format");
        	}
    		if(r>0) {
    		System.out.println(format((circle.getArea())));
    		}
            break;
        case 2://Rectangle
            double x1 = input.nextDouble();
            double y1 = input.nextDouble();
            double x2 = input.nextDouble();
            double y2 = input.nextDouble();
            
            点1 leftTopPoint = new 点1(x1,y1);
            点1 lowerRightPoint = new 点1(x2,y2);
            
            Rectangle rectangle = new Rectangle(leftTopPoint,lowerRightPoint);
            
            printArea(rectangle);
            break;
        }
        
    }
    public static void printArea(Shape circle){
        System.out.println(format(circle.getArea()));
    }   
	public static String format(double value) {
	    return String.format("%.2f", value).toString();
	}
}
class 点1{
  private double x;
   private double y;
   
public 点1(double x, double y) {
	super();
	this.x = x;
	this.y = y;
}
public double getX() {
	return x;
}
public void setX(double x) {
	this.x = x;
}
public double getY() {
	return y;
}
public void setY(double y) {
	this.y = y;
}
public 点1() {
	super();
}

}
class Shape{
	public Shape() {
		
	}
	public double getArea(){
		return getArea();
	}
}
class Rectangle extends Shape{
	private 点1 左上角点;
	private 点1 右下角点;
	
	public Rectangle(点1 左上角点, 点1 右下角点) {
		super();
		this.左上角点 = 左上角点;
		this.右下角点 = 右下角点;
	}
	public 点1 get左上角点() {
		return 左上角点;
	}
	public void set左上角点(点1 左上角点) {
		this.左上角点 = 左上角点;
	}
	public 点1 get右下角点() {
		return 右下角点;
	}
	public void set右下角点(点1 右下角点) {
		this.右下角点 = 右下角点;
	}
	public double get长() {
		return Math.abs(左上角点.getX()-右下角点.getX());
	}
	public double get宽() {
		return Math.abs(左上角点.getY()-右下角点.getY());
	}
	public double getArea() {
		return get长()*get宽();
	}
}
class Circle extends Shape{
    private double 半径=-1;

	

	public Circle(double 半径) {
		super();
		this.半径 = 半径;
	}

	public double get半径() {
		return 半径;
	}

	public void set半径(double r) {
		if(r<=0)
			System.out.println("Wrong Format");
		else
		this.半径 = r;
	}
	
    public double getArea() {
    	double s;
    	s=Math.PI*半径*半径;
    	return s;
    }
}

——1.2测验4-抽象类与接口

1)类图

2)生成报表

(绿色环形区域即被测量维度的期望值,维度上的点则是测量得到的实际值)

据报表分析:平均圈复杂度和函数深度都在合理范围内,代码质量中等。且平均每个类的方法数(Methods/Class)也在期望范围内,说明对类中方法的分配也较为妥当。

3)类设计
✔️ 继承关系:Shape做抽象形状类,有getarea方法,三角形类和矩形类继承Shape类,并覆盖其getarea方法。

✔️ 组合关系:矩形有四个点,故点类是矩形类为组合关系
✔️ Shape类实现Comparable接口:实现了对按面积大小进行对象数组的排列。

相关知识点如下:

接口 Comparable
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

Comparable的compareTo方法
比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

故可写Shape类


class Shape implements Comparable<Shape>{
	public Shape() {
		
	}
	public double getArea(){
		return getArea();
	}
	@Override
	public int compareTo(Shape o) {
		// TODO Auto-generated method stub
		 if(this.getArea()>o.getArea()){
	            return 1;
	        }else if(this.getArea()<o.getArea()){
	            return -1;
	}
		return 0;
}
}


4)代码如下

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
    	int flag=0;
    	ArrayList<Shape> shape=new ArrayList();
        Scanner input = new Scanner(System.in);
        while(flag==0) {
        int choice = input.nextInt();
        switch(choice) {
        case 1://Circle
        	double r=input.nextDouble();
        	Shape circle = new Circle(r);
        	if(r<=0) {
        		System.out.println("Wrong Format");
        	}
    		if(r>0) {
    			shape.add(circle);
    			//printArea(circle);
    		}
            break;
        case 2://Rectangle
            double x1 = input.nextDouble();
            double y1 = input.nextDouble();
            double x2 = input.nextDouble();
            double y2 = input.nextDouble();
            
            点1 leftTopPoint = new 点1(x1,y1);
            点1 lowerRightPoint = new 点1(x2,y2);
            
            Rectangle rectangle = new Rectangle(leftTopPoint,lowerRightPoint);
            shape.add(rectangle);
            //printArea(rectangle);
            break;
        case 0:
        	flag=1;break;
        }
        }
        Collections.sort(shape);
        for(int i=0;i<shape.size();i++) {
        	if(shape.get(i)!=null)
        	printArea(shape.get(i));	
        }
    }
    public static void printArea(Shape circle){
        System.out.print(format(circle.getArea())+" ");
    }   
	public static String format(double value) {
	    return String.format("%.2f", value).toString();
	}
}
class 点1{
  private double x;
   private double y;
   
public 点1(double x, double y) {
	super();
	this.x = x;
	this.y = y;
}
}
class Shape implements Comparable<Shape>{
	public Shape() {
		
	}
	public double getArea(){
		return getArea();
	}
	@Override
	public int compareTo(Shape o) {
		// TODO Auto-generated method stub
		 if(this.getArea()>o.getArea()){
	            return 1;
	        }else if(this.getArea()<o.getArea()){
	            return -1;
	}
		return 0;
}
}
class Rectangle extends Shape{
	private 点1 左上角点;
	private 点1 右下角点;
	
	public Rectangle(点1 左上角点, 点1 右下角点) {
		super();
		this.左上角点 = 左上角点;
		this.右下角点 = 右下角点;
	}
	public double get长() {
		return Math.abs(左上角点.getX()-右下角点.getX());
	}
	public double get宽() {
		return Math.abs(左上角点.getY()-右下角点.getY());
	}
	public double getArea() {
		return get长()*get宽();
	}
}
class Circle extends Shape{
    private double 半径=-1;
	public Circle(double 半径) {
		super();
		this.半径 = 半径;
	}
	public double get半径() {
		return 半径;
	}
	public void set半径(double r) {
		if(r<=0)
			System.out.println("Wrong Format");
		else
		this.半径 = r;
	}
    public double getArea() {
    	double s;
    	s=Math.PI*半径*半径;
    	return s;
    }
}

2、菜单计价程序-5
1)完成情况

2)类图

3)生成报表

(绿色环形区域即被测量维度的期望值,维度上的点则是测量得到的实际值)

据报表分析:
①平均圈复杂度和函数深度超标,圈复杂度大,说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。
②耦合度过高:类与类间分支嵌套过多

4)类设计
✔️ 判断输入格式:
利用正则表达式判断格式,这里给出我写的部分正则表达式作为例子

String regex4 = "[\\u4e00-\\u9fa5]{0,}[ ]\\d{0,}";//非特色菜菜谱
    String regex3 = "[\\u4e00-\\u9fa5]{0,}[ ][\\u4e00-\\u9fa5]{0,}[ ]\\d{0,}[ ][T]";//特色菜谱
    String regex6 = "\\d[ ](delete)";//删除情况

✔️ 菜单里新增特色菜的处理方法:
在dish类里增加特色菜(boolean)属性(默认是false),输入菜单时用正则表达式判断,如果输入的是特色菜就把特色菜属性改为true。
dish类代码实现如下:

class Dish {
String name;//菜品名称
int unit_price; //单价
boolean 特色菜=false;
String 口味;

public void set口味(String 口味) {
	this.口味 = 口味;
}
public Dish(String name,int unit_price) {
	this.name=name;
	this.unit_price=unit_price;
}
public int getPrice(int portion){//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
	double p;
if(portion==1)
p=unit_price;
else if(portion==2)
p=unit_price*1.5;
else if(portion==3)
p=unit_price*2;
else return 0;
return (int)Math.round(p);
}
}

✔️ 输入订单时对用户电话号和姓名的判断与记录:
用正则表达式判断输入是否正确。
在Table类((记录输出时所需每桌订单的信息))里增加name属性,number属性。
✔️ 将输出以用户姓名首字母从小到大的顺序排序:
处理方法:
Table类要实现Comparable接口,Comparable的compareTo方法比较此对象与指定对象的顺序。

class Table implements Comparable<Table>{
    .....
}
Table类的comeparable方法代码入下:
@Override
	public int compareTo(Table o) {
		// TODO Auto-generated method stub
		 if(this.s.charAt(0)>o.s.charAt(0)){
	            return 1;
	        }else if(this.s.charAt(0)<o.s.charAt(0)){
	            return -1;
	}
		return 0;
}
:heavy_check_mark:新增了记录每桌的特色菜点菜情况的类(用于输出每桌特色菜点菜情况):

该类里最主要有川菜口味度数组,晋菜口味度数组,川菜口味度数组等属性。如果该桌没有点特色菜,则该几个数组都为null;如果该桌点特色菜了,则记录下来其口味度,通过动态数组的add方法将口味度添加到其对应的口味度数组。

这样下来,数组的大小为点该口味的特色菜的份数,数组里的值为该口味
的特色菜的口味度。

该类具体代码体现如下:


class 特色菜记录{
	String 级别;
	String 种类;
	int portion;
	 ArrayList<Integer> 川菜口味度=new ArrayList();
	    ArrayList<Integer> 浙菜口味度=new ArrayList();
	    ArrayList<Integer> 晋菜口味度=new ArrayList();
	
	public 特色菜记录(ArrayList<Integer> 川菜口味度, ArrayList<Integer> 浙菜口味度,ArrayList<Integer> 晋菜口味度) {
			super();
			this.川菜口味度 = 川菜口味度;
			this.浙菜口味度 = 浙菜口味度;
			this.晋菜口味度 = 晋菜口味度;
		}
	public void get种类() {//该方法用来输出每桌点的特色菜的平均口味度
		int sum7=0,sum8=0,sum9=0;
		int flag7=0,flag8=0,flag9=0;
		int i=0,j=0,k=0;
		for(i=0;i<川菜口味度.size();i++) {
			if(川菜口味度.get(i)!=null) {
				sum7=sum7+川菜口味度.get(i);
				flag7=1;
			}
		}
		for(j=0;j<晋菜口味度.size();j++) {
			if(晋菜口味度.get(j)!=null) {
				sum8=sum8+晋菜口味度.get(j);
				flag8=1;
			}
		}
		for(k=0;k<浙菜口味度.size();k++) {
			if(浙菜口味度.get(k)!=null) {
				sum9=sum9+浙菜口味度.get(k);
				flag9=1;
			}
		}
		if(flag7==1) {
			int tem=Math.round(sum7/((float)i));
			String 级别 = null;
			switch(tem) {
			case 0:级别="不辣";break;
			case 1:级别="微辣";break;
			case 2:级别="稍辣";break;
			case 3:级别="辣";break;
			case 4:级别="很辣";break;
			case 5:级别="爆辣";break;
			}
			System.out.print(" "+"川菜"+" "+i+" "+级别);	
			
		}
		if(flag8==1) {
			int tem=(int)Math.round(sum8/(float)j);
			String 级别 = null;
			switch(tem) {
			case 0:级别="不酸";break;
			case 1:级别="微酸";break;
			case 2:级别="稍酸";break;
			case 3:级别="酸";break;
			case 4:级别="很酸";break;
			}
			System.out.print(" "+"晋菜"+" "+j+" "+级别);	
		}
		if(flag9==1) {
			int tem=(int)Math.round(sum9/(float)k);
			String 级别 = null;
			switch(tem) {
			case 0:级别="不甜";break;
			case 1:级别="微甜";break;
			case 2:级别="稍甜";break;
			case 3:级别="甜";break;
			
			}
			System.out.print(" "+"浙菜"+" "+k+" "+级别);	
		}
	}
}
**2、菜单计价程序-4**

1)完成情况

2)类图

3)生成报表

(绿色环形区域即被测量维度的期望值,维度上的点则是测量得到的实际值)

据报表分析:
①平均圈复杂度和函数深度超标,圈复杂度大说明程序代码的判断逻辑复杂,代码质量较低(其实是因为我把判断输入是否正确的代码大部分都放在了主函数,所以主函数写的过于冗长)
②耦合度过高:类与类间分支嵌套过多。

4)代码分析与类设计
✔️ 本题难点在于判断输入格式是否正确:
比较考验正则表达式的设计和正确书写,这里给出我写的部分正则表达式作为例子:

String regex = "[\\u4e00-\\u9fa5]{0,}[ ]\\d{0,}";//非特色菜菜谱
String regex1 = "[\\u4e00-\\u9fa5]{0,}[ ]\\d{0,}[ ]\\d{0,4}[ ][T]";//特色菜谱
 String regex3 = "(table)[ ]([1-4][0-9]*|[5][0-5]*)[ ]\\d{4}[/]\\d{1,}[/]\\d{1,2}[ ]([0-1]?[0-9]|2[0-3])/([0-5][0-9])/([0-5][0-9])";//订单信息
除了判断格式,还有日期是否合理且在[2022.1.1-2023.12.31]范围内的判断,这里我的处理方法先判断是专门写一个类。该类代码如下:
class 判断table行是否合法{
	String tian;
	public 判断table行是否合法(String tian, String zhuo) {
		super();
		this.tian = tian;
		this.zhuo = zhuo;
	}
	String zhuo;
	boolean 日期合法() {//判断日期是否合法且在范围内
		String[]arr=tian.split(" ");//2023/2/1 14/20/00
		String[]brr=arr[0].split("/");
		boolean judge=false;
		int nian=brr[0].length();
		int yue=brr[1].length();
		int ri=brr[2].length();
		String[]crr=arr[1].split("/");
		int shi=crr[0].length();
		int fen=crr[1].length();
		int miao=crr[2].length();
		int year=Integer.parseInt(brr[0]);
	  	int month=Integer.parseInt(brr[1]);
	  	int day=Integer.parseInt(brr[2]);
		judge=judgeday(month,day,year);
		if(judge&&nian==4&&(yue==1||yue==2)&&(ri==1||ri==2)&&(shi==1||shi==2)&&(fen==1||fen==2)&&(miao==1||miao==2)) {
			return true;
		}
		else
			return false;
	}
	public int tday(int year){//判断是否为闰年
		if((year%4==0&&year%100!=0)||year%400==0) {
			return 29;
		}
		else
			return 28;
		
	}
	public boolean judgeday(int month,int day,int year){//判断日和月是否合法
		switch(month) {
		case 1:if(day<=31&&day>0) return true;else return false;
		case 2:int d=tday(year);if(day<=d&&day>0) return true;else return false;
		case 3:if(day<=31&&day>0) return true;else return false;
		case 4:if(day<=30&&day>0) return true;else return false;
		case 5:if(day<=31&&day>0) return true;else return false;
		case 6:if(day<=30&&day>0) return true;else return false;
		case 7:if(day<=31&&day>0) return true;else return false;
		case 8:if(day<=31&&day>0) return true;else return false;
		case 9:if(day<=30&&day>0) return true;else return false;
		case 10:if(day<=31&&day>0) return true;else return false;
		case 11:if(day<=30&&day>0) return true;else return false;
		case 12:if(day<=31&&day>0) return true;else return false;
		default:return false;
	}
}

	
}
:heavy_check_mark: 新增特色菜种类: 在Dish类里新增(boolean)特色菜属性,赋值为false,如果输入菜单时有‘T’则把该属性改为true。

三、踩坑心得

  1. 写正则表达式

由于正则表达式过于不熟练,导致第四次大作业好多测试点都没有过,第五次大作业出了后,我上网看了有关正则表达式的文章,学习了一下后运用到代码里,发现真的很方便。
这里给出我当时学习正则表达式用的文章:
[]:http://t.csdn.cn/ZmH67

  1. Comparable接口

期中考试考到了接口,Comparable的comepareTo方法搭配Collection.sort()方法可以实现对对象数组的排序,十分方便。

  1. 格式错误的踩坑

错误格式是因为漏了空格或多了回车,这需要不断调试代码并且对比题干才可以发现这类错误的原因。在拿到题目的时候。

  1. 审题与类设计
    java是面向对象的语言,在题目给出后,应该先认真审题,将类都设计好,不然到后续发现漏了题目要求的时候,改起来很复杂。
    同样,为了方便修改代码内容,应该降低类之间耦合性,熟悉类间关系进行设计。

四、主要困难与改进建议

①主要困难:
基础知识薄弱,对于很多新的语法不会用不敢用,如最近接触的哈希,Hashmap,Hashset。

②改进建议:
希望留大作业时不要只留一道菜单题,应该多留几道不算难但能锻炼学生灵活掌握新知识的题。

五、总结

经历了java第二个学习阶段,我深刻认识到在面向对象过程中对类的设计是多么重要,类与类间关系,接口和抽象类的设计等等,都是对我的考验。代码越好,代码的圈复杂度就越低,类与类之间关系明确,代码的可维护性也高。
再回归具体知识点,在本阶段学习中我训练了继承和接口的使用,也自主设计了面向对象的代码,并逐步接触了一些比较好用的类与方法,也对动态数组的使用逐渐熟悉。希望在学好目前的知识的基础上,能学到更深的知识。

posted on 2023-05-16 22:06  七濑子(上学版)  阅读(49)  评论(0)    收藏  举报