第一次博客作业(2022/4/3)
经过前五周的学习,我们巩固了java中的语法知识,通过雨刷问题的迭代编程、慕课spoc课程与线下课程相结合、pta作业与超星作业结合,我们初步并进一步接触到面向对象编程与类设计,并在实践中得到了进一步体会,写代码并不只是写代码,更要做好顶层设计。
-
(一)前言
(1)知识点
1.涉及到Java的一些基础语法:Scanner的使用、String类的方法使用、数据的输出等
2.类的封装、继承、多态性使用方法、类之间的关系以及接口的应用
3.排序算法,ArrayList 工具类的使用
4.“单一职责”原则和“开-闭”原则
5.字符串匹配,线和三角形的计算
(2)题量
截至目前,pta已布置五次作业,题量为4+9+3+3+2;

慕课作业有两次,对应分数的相加相乘输出与用Display和Clock类实现时钟两道题;
学习通上实验已发布三次,一次为Java程序控制结构,一次为类与对象,一次为继承与多态;
雨刷问题迭代到第五代。
(3)难度
pta五次作业难度分别为三颗星,两颗星,三颗星,四颗星,四颗星。(无明确标准,仅供参考)
慕课作业的算法有可斟酌,类的复杂度不大。
学习通的实验有一定难度,需要细细设计,清晰逻辑,掌握结构。
雨刷问题的迭代已大致结束,每次都是按一定的模式结构或原则要求不断将代码改善打磨。
-
(二)设计与分析
(1)
pta题目集一主要通过日期类设计实现日期下一天,上一天,两个日期相差天数的功能,重点由类中函数设计转为类的关系和功能设计。
下图是题目提供的两种类聚合方法。


显然后者更能实现减少耦合,而且更易懂,将Month,Year,Day三个实体类交给DateUtil类来管理,完成日期增减判断等操作,得出结果。
pta题目集二通过身体质量指数(BMI)测算、长度质量计量单位换算、奇数求和、房产税费计算、游戏角色选择 、学号识别、巴比伦法求平方根近似值、二进制数值提取、判断三角形类型九道题,让我们复习了Java中的语法部分,更加熟练算法,细节上也有考量。
判断三角形类型核心代码如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); float a = in.nextFloat(); float b = in.nextFloat(); float c = in.nextFloat(); if(a>=1 && a<=200 && b>=1 && b<=200 && c>=1 && c<=200) { 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==b && Math.abs(a*a+b*b-c*c)<0.001)|| (b==c && Math.abs(b*b+c*c-a*a)<0.001) || (a==c && Math.abs(a*a+c*c-b*b)<0.001)) { System.out.println("Isosceles right-angled triangle"); } else if(a==b ||a==c || b==c) { System.out.println("Isosceles triangle"); } else if(Math.abs(a*a+b*b-c*c)<0.001 || Math.abs(b*b+c*c-a*a)<0.001 || Math.abs(a*a+c*c-b*b)<0.001) { System.out.println("Right-angled triangle"); } else { System.out.println("General triangle"); } } } else { System.out.println("Wrong Format"); } } }
通过if - else if 的判断语句,一步步判断三角形类型,注意等腰直角三角形的判定中,因为浮点型相等直接用等于号来判定不合理,可以通过差值小于零点零零一来表示。
pta题目集三通过字母-数字转换、串口字符解析、 String的格式判断与内容提取三道题来加强我们对字符串的存储查找等操作的熟练度,以输出为导向,不断调试格式,调整内容,得到最终结果。
String的格式判断与内容提取核心代码如下:
import java.util.Scanner; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { Scanner in = new Scanner (System.in); int count = 0; String s = in.nextLine(); char [] s1 = s.toCharArray(); for(int i=s.length();i>=1;i--){ int ch=s.charAt(i-1); if(ch>=48 && ch<=57) count++; } StringBuffer str = new StringBuffer(); Pattern pattern = Pattern.compile("^[0-9]*$"); Pattern pattern1 = Pattern.compile("^[\\s]+$"); if(!pattern.matcher(s).matches() || pattern1.matcher(s).matches() || count % 8 != 0) { System.out.println("Wrong Format"); } else { for(int i =1;i <= count / 8;i++) { if(i != count / 8) { if(s.substring(i * 8 - 8, i * 8 - 2).equals("202017") || s.substring(i * 8 - 8, i * 8 - 2).equals("202061")) { str.append(s.substring(i * 8 - 4 , i * 8) + " "); } } else { if(s.substring(i * 8 - 8, i * 8 - 2).equals("202017") || s.substring(i * 8 - 8, i * 8 - 2).equals("202061")) { str.append(s.substring(i * 8 - 4)); } } } System.out.println(str.toString()); } } }
题目要求判断的是学号,我以8个字符为单位进行匹配判断,以4个字符为单位输出,用java.util.regex.Pattern里的匹配函数。
pta题目集四通过点线性系列123题,不仅促使我们去复习与学习点与线、点与三角形间关系,距离的判断,也加强了我们对字符串匹配,格式化输出的理解。
点线性系列1-计算两点之间的距离核心代码如下:
import java.util.Scanner; import java.util.regex.*; public class Main { public Main() { // TODO Auto-generated constructor stub } public static void main(String[] args) { Scanner in = new Scanner(System.in); String coordinate = in.nextLine(); String pattern1 = "^[-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?\\s+[-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?$"; String pattern2 = "([-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?(\\s+)?){3,}" ; if(Pattern.matches(pattern2, coordinate)) { System.out.println("wrong number of points"); }else if(!Pattern.matches(pattern1, coordinate)) { System.out.println("Wrong Format"); } else { String[] zuo = coordinate.split("\\s+"); String[] zuo1 = zuo[0].split(","); String[] zuo2 = zuo[1].split(","); double x1 = Double.parseDouble(zuo1[0]); double y1 = Double.parseDouble(zuo1[1]); double x2 = Double.parseDouble(zuo2[0]); double y2 = Double.parseDouble(zuo2[1]); System.out.println(Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2))); } }
通过学习正则表达式,将字符串匹配简单化,但也增加了不少风险,之前因为“([0]|[1-9]+)?(\\.\\d+)?”这一句中本没有用|隔开,逗号和整数的判断没有整到一个括号里,代码之前的匹配是不完善的,所以测试点也没有完全过。
pta题目集五通过图形卡片排序和分组游戏,给了相应的指导书,涉及Comparator 接口的运用,需要设定图形类的排序方法,更改数据可以实现倒序;分组运用判断类即可实现。
程序实现了图形类的继承,相应方法的复写。
部分代码如下:
class DealCardList { ArrayList<Card> card = new ArrayList<Card>(); ArrayList<Card> card1 = new ArrayList<Card>(); ArrayList<Card> card2 = new ArrayList<Card>(); ArrayList<Card> card3 = new ArrayList<Card>(); ArrayList<Card> card4 = new ArrayList<Card>(); public DealCardList() { } public DealCardList(ArrayList<Integer> list) { for (Integer elem : list) { switch (elem){ case 1: card.add(new Card(new Circle(Main.input.nextDouble())));break; case 2: card.add(new Card(new Rectangle(Main.input.nextDouble(),Main.input.nextDouble())));break; case 3: card.add(new Card(new Triangle(Main.input.nextDouble(),Main.input.nextDouble(),Main.input.nextDouble())));break; case 4: card.add(new Card(new Trapezoid(Main.input.nextDouble(),Main.input.nextDouble(),Main.input.nextDouble())));break; } } }
abstract class Shape { private String nameString; public Shape() { // TODO Auto-generated constructor stub } public Shape(String nameString) { this.nameString = nameString; } public String getNameString() { return nameString; } public void setNameString(String nameString) { this.nameString = nameString; } public abstract double getArea() ; public abstract boolean validate(); public abstract String toString(); }
@Override public String toString() { // TODO Auto-generated method stub return "Triangle"; }
@Override public int compareTo(Card o) { if(shape.getArea() > o.shape.getArea()) return -1; else if(shape.getArea() < o.shape.getArea()) return 1; else return 0; }
(2)雨刷的迭代
1:老师要求用c语言、Java语言和python语言实现雨刷问题的编程模拟。可以发现这时候c语言没有什么优越性,而Java和python编写也比较困难。
2:需求不变,采用面向对象技术,合理设计实体类、业务(控制)类、接口类及各个类之间的关系。刚接触面向对象,这时候还体会不到它的优越性,写各种类,会感觉到麻烦,类之间的关系也是不清楚的,主要是为了实现雨刷的功能。
3: 进一步规范编码格式,务必符合SRP(Single Responsibility Principe,单一职责原则)以及Demeter法则(Law of Demeter)(强制要求)。这时候开始清晰类的封装,明白信息的封装实现了更好的降低风险的交流,也开始了解到单一职责原则之所以成为原则的道理,代码得到更规范的编写,类的方法实现的功能也逐渐清晰。
4:设计必须符合MVC模式,且尝试嵌入单例模式(独身模式)。这时候开始更了解类与类的关系,明白关联,聚集,继承,明白关联有些泛泛而谈,明白组合和聚合的区别。MVC软件架构模式的运用让我们认清客户端,信息处理,数据库三者独立又紧密的关系,明白类并不是单打独斗的笨蛋,而单例模式让一个类负责创建自己的对象,同时确保只有单个对象被创建,更一步封装又稳固了信息及其传递。
5:需求变更为该系统可以适用多种雨刷系统,实现类的继承、“开-闭”原则、里氏代换原则、依赖倒转原则以及合成复用原则(强制要求)。面对这个需求,我们运用了类的继承,让雨刷实现多态,用户可以按需选择不同档位的雨刷。此时我们已经学完了面向对象的七大原则,并在雨刷问题中实现了初步的运用。复写让相同的语句实现了不同的操作,多态为面向对象注入了灵魂。
如图是最终代的雨刷类图:

此时类与类的关系已经开始简单又复杂,
而雨刷迭代的思路我们也运用到了实验二三农夫过河的迭代中,只是那里有一些更小的要求,更多的尝试。
-
(三)踩坑心得
#
涉及到循环时设置的变量应注意后期需不需要归零(或一)或者需要别的运算确保算法正常运行。
eg:题目集(3)的第二题,循环定位开始的位置i需要不断改变,计数count需要清零。
核心代码如下:
import java.util.Scanner; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { Scanner in = new Scanner (System.in); int count = 0; int flag = 0; String s = in.nextLine(); char [] s1 = s.toCharArray(); //int [] nums = new int[20]; StringBuffer str = new StringBuffer(); if(s1.length < 11) { System.out.println("null data"); } else { for(int j = 0;j < s1.length;j++) { if(s1[j] == '0') { flag = 1; break; } } if( flag == 0) { System.out.println("null data"); } else{ int num = 1; int nums = 0; for(int i = nums; i < s1.length;) { if(s1[i] == '0') { if(s1.length - 1 - i < 10) { break; }else { for (int j = i + 1; j < i + 10;j++) { if( s1[j] == '1') { count ++; } } if( s1[i + 10] != '1' && count % 2 ==0) { System.out.println(num + ":"+ "validate error"); num ++; i = i + 11; count = 0; } else if( s1[i + 10] != '1') { System.out.println(num + ":"+ "validate error"); num ++; i = i + 11; count = 0; } else if(count % 2 ==0) { System.out.println(num + ":"+ "parity check error"); num ++; i = i + 11; count = 0; } else { System.out.print(num + ":"); System.out.println(s.substring( i + 1, i + 9)); num ++; i = i + 11; count = 0; } } } else { i++; } } } } } }
#
判断字符串相等应该用equals方法,两字符串间之间加等号是在判断二者是否拥有相同的管理者;判断字符相等时记得加 ' ' 单引号,否则数字会被转成对应ASCII码值的字符。
(频繁频繁频繁误写.....)
#
测试永远是检查一个代码是否有bug的最简洁的方法,在写代码时可以边写边测试,及时发现代码错误。当功能叠在一起时,测试反而不那么容易了。
eg pta题目集四的第二题,因为用正则表达式判断时,一旦错误,很难判断出,所以可以一边写if - else判断语句一边用用例点测试,来判断各种格式错误。
String coordinate = in.nextLine(); String pattern = "^[12345]\\:([-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?(\\s+)?){2,}" ; String pattern1 = "^[1]\\:[-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?\\s+[-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?$"; String pattern2 = "^[23]\\:([-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?(\\s+)?){3}" ; String pattern3 = "^[45]\\:([-+]?([0]|[1-9]+)?(\\.\\d+)?\\,[-+]?([0]|[1-9]+)?(\\.\\d+)?(\\s+)?){4}" ;
- (四)总结
(1)综合性知识小节
#原则至上
优秀的代码应该具有可扩展,可维护和可测试性。
面向对象三大基础特性:封装 继承 多态
类的种类有三种:实体类、业务类、接口类。
三种类的关系(体现耦合性)越松散越好。
ps:耦合性为类之间的关系,内聚性为类内的关系。
面向对象的七大原则:一、单一职责原则(内聚性),二、开闭原则(开放扩展、关闭修改,在代码原有基础上只增不改),三、里氏代换原则(父类必有子类方法),四、合成复用原则(新对象通过向旧对象的委派达到复用目的),五、依赖倒转原则(抽象层做依赖,具体层不做依赖),六、接口隔离原则(一个接口里的方法最少为一个),七、迪米特法则。
接口(interface)可继承(implements),类抽象类。
abstract类不可定义对象,但可用于继承。 子类需重写抽象类方法(否则仍为抽象类)。
final类不可有子类,其声明的变量为常量,其声明的方法不可覆写。
三个修饰词:protected(强于public弱于private,子类可调用其变量与方法)
private(私有权限,完成类的封装,用于成员变量和方法,无私有类)
public(public函数是用来提供服务的,一个.java文件只有一个public类)
如果某成员用static修饰,那它就属于整个类,可通过“类名.成员名”来访问。
面向对象五种关系(本质为调方法):
一、关联
二、聚集(又叫整体和部分间的关系,分为聚合和组合,区别在于前者中整体和部分生存期不同而后者相同)
三、依赖
四、继承(可用继承(extends)的两种情况:整体与部分,大类和小类。)
特点:1.单继承,一个子类只有一个父类
2.子类可以拥有父类的属性和方法
3.子类可以拥有自己的属性和方法
4.子类可以重写(@Override)覆盖父类的方法
五、实现
ps:若为其属性,二者定为关联或聚集关系。
MVC软件开发架构模式
Model --- 数据封装和处理
View --- 数据显示
Controller --- 业务逻辑和响应策略
单例模式(Singleton)
将构造方法private,让一个类负责创建自己的对象,同时确保只有单个对象被创建。
这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
合成复用原则与多态有关,不同的对象接收到同一消息时会产生不同操作。
其优点有:运行时多态,动态联编。
(2)预计进一步学习及研究内容
1.了解工具、集合框架类的方法
2.阅读阿里巴巴Java开发手册
3.继续读厚厚的《Java语言程序设计》
(3)对课程组织等方面的建议及意见
无
浙公网安备 33010602011771号