第二次Blog作业
前言
这一次Blog主要是针对题目集4~6的总结。这三次题目集中题目集4的题量较少但题目相对偏难,而题目集5~6的题量相对偏多但难度偏低,前3到4题都是很简单的容易题,但分值也很低,而后一两题的难度偏高分值也高。其中题目集4有关的知识点有正则表达式、聚合、继承;题目集5有关的知识点主要是排序、正则表达式、聚合;题目集6有关的知识点主要是正则表达式、继承与多态、接口。总的来说包括的知识点不多也不会很难,但是题量有点大时间也有点紧迫。
设计与分析
①题目集4(7-2)、题目集5(7-4)两种日期类聚合设计的优劣比较:
从代码本身来讲,题目集5的简易度较为简单,因为题目集4将日期属性放在各个不同类中,例如要调用到某个日期的"year"时,需要用到"getDay().getMonth().getYear().getValue()";而题目集5将属性都放在了DateUtil这个类中,同样需要调用某个日期的"year"时,只需要用到"getYear().getValue()"。但同样也导致题目集5中大多数方法都集中在DateUtil这个类中,有点头重脚轻的感觉,而题目集4却是分得比较均匀,甚至很多方法用途类似,可以添加父类,代码就会显得更简单。从对象来讲,题目集4的三个属性是一环扣一环的,之间联系紧密,而题目集5的三个属性是分散的,其中一个属性有问题其他不会受影响,这就导致在判断日期是否合法的编写上题目集4相对于题目集5来说更为简易。
②题目集4(7-3)、题目集6(7-5、7-6)三种渐进式图形继承设计的思路与技术运用(封装、继承、多态、接口等)
题目集4(7-3)设计思路:创建一个Shape类写出求图形面积的公有方法,Shape类和Circle类都继承自它,Ball类继承自Circle类,再在其他三个类中分别重写。
这是在Shape类中的求面积方法:
public double getArea(){ return 0.0; }
这是Circle类中求面积方法:
public double getArea() { return 3.14*radius*radius; }
这是Rectangle类中求面积方法:
public double getArea() { return width*length; }
这是Ball类中求面积方法:
public double getArea() { return 4*super.getArea(); }
这次作业中主要运用继承,而继承的作用不大,更多是初识继承,了解其内容而已。
题目集6(7-5)设计思路:编写一个抽象类Shape,其中编写getArea()方法和validate()方法都为抽象方法,其余三个类都继承自它。而我当时对于ArrayList 的应用并不熟悉,多态的运用上就自己对于每个属性都创建了数组,输入时运用数组。
这是我的Main类:
public class Main { public static void main(String[] args){ Scanner input=new Scanner(System.in); int a=input.nextInt(); int b=input.nextInt(); int c=input.nextInt(); double allcircle=0; double allrectangle=0; double alltriangle=0; double allshape; if(a<0||b<0||c<0) System.out.printf("Wrong Format"); else{ double[] radius =new double[a]; double[] width =new double[b]; double[] length =new double[b]; double[] side1 =new double[c]; double[] side2 =new double[c]; double[] side3 =new double[c]; double[] array =new double[a+b+c]; for (int i = 0; i < a; i++) { radius[i] = input.nextDouble(); } for (int i = 0; i < b; i++) { width[i] = input.nextDouble(); length[i] = input.nextDouble(); } for (int i = 0; i < c; i++) { side1[i] = input.nextDouble(); side2[i] = input.nextDouble(); side3[i] = input.nextDouble(); } if (a >= 0 && b >= 0 && c >= 0) { System.out.println("Original area:"); } for (int i = 0; i < a; i++) { Circle circle = new Circle(radius[i]); if (circle.validate()) allcircle = allcircle + circle.getArea(); else { allcircle = -1; break; } System.out.printf("%.2f ", circle.getArea()); array[i] = circle.getArea(); } for (int i = 0; i < b; i++) { Rectangle rectangle = new Rectangle(width[i], length[i]); if (rectangle.validate()) allrectangle = allrectangle + rectangle.getArea(); else { allrectangle = -1; break; } System.out.printf("%.2f ", rectangle.getArea()); array[a + i] = rectangle.getArea(); } for (int i = 0; i < c; i++) { Triangle triangle = new Triangle(side1[i], side2[i], side3[i]); if (triangle.validate()) alltriangle = alltriangle + triangle.getArea(); else { alltriangle = -1; break; } System.out.printf("%.2f ", triangle.getArea()); array[a + b + i] = triangle.getArea(); } System.out.printf("\n"); if (allcircle != -1 && allrectangle != -1 && alltriangle != -1 ) { allshape = allcircle + allrectangle + alltriangle; System.out.printf("Sum of area:%.2f\n", allshape); System.out.println("Sorted area:"); if (array.length != 0) { double temp = 0; for (int i = 0; i < array.length; i++) { int min = i; for (int j = i; j < array.length; j++) { if (array[j] <= array[min]) { min = j; } } temp = array[min]; array[min] = array[i]; array[i] = temp; } } for (int i = 0; i < array.length; i++) { System.out.printf("%.2f ", array[i]); } System.out.printf("\n"); System.out.printf("Sum of area:%.2f", allshape); } } if(allcircle==-1||allrectangle==-1||alltriangle==-1) System.out.println("Wrong Format"); } }
很为复杂但是可以运行,但如果是现在的我来写我会运用ArrayList 来完成,这样实现的多态更为简便易懂。
题目集6(7-6)设计思路:使用接口GetArea,GetArea中只写一个求面积的抽象方法,Circle及Rectangle分别实现GetArea接口。
这是我Circle类对于该抽象方法的实现:
public double getArea() { return 3.1415926*radius*radius; }
这是我Rectangle类对于该抽象方法的实现:
public double getArea() { return length*width; }
这道题目主要也是对于接口的初识,其作用并不明显。
③对三次题目集中用到的正则表达式技术的分析总结
题目集6中正则表达式的三个题目是最简单的,都是判断字符串,都只运用了用于检测字符串是否匹配给定的正则表达式matches() 方法。
对QQ号的判断(对于特定位数及开头字符的特定要求的数字字符串的判断):
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner input=new Scanner(System.in); String qq=input.next(); String regex="[1-9][0-9]{4,14}"; boolean flag=qq.matches(regex); if(flag){ System.out.println("你输入的QQ号验证成功"); }else { System.out.println("你输入的QQ号验证失败"); } } }
对验证码的判断(对于由特定位数数字或者字母(包含大小写)组成的字符串的判断):
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner input=new Scanner(System.in); String str=input.next(); String regex="[0-9]{4}+[a-zA-Z]{4}+[0-9a-zA-Z]*|[a-zA-Z]{4}+[0-9]{4}+[0-9a-zA-Z]*{4}"; boolean flag=str.matches(regex); if(flag){ System.out.print(str+"属于验证码"); }else System.out.print(str+"不属于验证码"); } }
对学号的判断(对于特定位数及特定位置特定要求的数字字符串的判断):
import java.util.Scanner; public class Xuehao { public static void main(String[] args){ Scanner input=new Scanner(System.in); String ID=input.next(); String regex="20201[1-7][0-3][1-9]|20201[1-7]40|202061[0-3][1-9]|20206140|20207[1-3][0-3][1-9]|20207[1-3]40|20208[1-2][0-3][1-9]|20208[1-2]40"; boolean flag=ID.matches(regex); if(flag){ System.out.print("正确"); }else System.out.print("错误"); } }
题目集5中正则表达式的题目有点难度,是对关键字的判断(查找输入字符串中是否含有指定字符串),主要还运用到了Map接口。且出了运用到了matches() 方法以外还有能够按照能够匹配的子串将字符串分割后返回列表的split 方法、用于编译正则表达式,生成一个 Pattern 对象的compile 函数、能够将字符串替代的replace()方法。
下面是我的源代码:
import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Guangjianci { public static void main(String[] args) { // TODO Auto-generated method stub Scanner input=new Scanner(System.in); String a; StringBuilder ss=new StringBuilder(); Map<String, Integer> map=new HashMap<String, Integer>(); String []key= { "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" }; int j=0; for(int i=0;;i++) { a=input.nextLine(); if(a.equals("exit")) break; if(a.matches("(.*)//(.*)")) {String b[]=a.split("//"); ss.append(b[0]+" "); //ss.append('\n'); } else {ss.append(a+" "); //ss.append('\n'); } } int count=0; String s=ss.toString(); // System.out.println(s); Pattern p=Pattern.compile("\"(.*?)\""); Matcher m=p.matcher(s); while(m.find()){ s=s.replace(m.group()," "); p=Pattern.compile("\"(.*?)\""); m=p.matcher(s); } p=Pattern.compile("/\\**(.*?)/"); m=p.matcher(s); while(m.find()){ s=s.replace(m.group()," "); // p=Pattern.compile("/\\*(.*?)\\*/"); m=p.matcher(s); } // System.out.println(s); if(s.isEmpty()) {System.out.println("Wrong Format"); System.exit(0); } s=s.replace("["," "); s=s.replace("]"," "); s=s.replace("-","a"); s=s.replace("*","a"); s=s.replace("/","a"); s=s.replace("+","a"); s=s.replace(">","a"); s=s.replace("=","a"); s=s.replace("!","a"); s=s.replace(":","a"); s=s.replace("\\","a"); s= s.replaceAll("[^a-zA-Z]", " "); String []s1=s.split("[ ' ']"); for(int i=0;i<s1.length;i++) {//System.out.println(s1[i]); for( j=0;j<key.length;j++) if(s1[i].equals(key[j])) { map.put(key[j], 0); } } for( int i = 0;i<s1.length;i++) { for( j=0;j<key.length;j++) if(s1[i].equals(key[j])) { count=map.get(key[j]); map.put(key[j], count+1); } } Set set=map.keySet(); Object[] arr=set.toArray(); Arrays.sort(arr); for(Object k:arr){ System.out.println(map.get(k)+"\t"+k); } } }
④题目集5(7-5)中Java集合框架应用的分析总结
这道题目是我学java以来花费时间最久和花费精力最多的题目,光是调试都上十次,从头调到尾,还拿小本本边算着来查找究竟是哪出现问题,但关键是花了这么久时间也没有做到测试点全过,待会儿我也会讲这题放在我的踩坑心得中重点讲诉。
而本题主要是对于集合框架的运用,集合框架有以下几个特点:
-
该框架必须是高性能的。基本集合的实现也必须是高效的。
-
该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
-
对一个集合的扩展和适应必须是简单的。
在本题中也是讲该特点表现得淋漓尽致。DateUtil中对于数据的运用大多都来自Year、Month、Day三个类中,这三个类可以定义不同属性的数据但对于DateUtil类来说并没有多大关系,就是将DateUtil类与三个类中定义的数据分隔开,我只是调用你,但我并不管你什么属性。
踩坑心得
主要对于题目集5(7-5)来说,在提交过程中总是发现所得日期与应有日期相差那么一两天,从各个方向进行调试,不断找原因,改代码。运用同样的算法,求前n天的功能正常值测试点能够但求下n天的正常值测试点过不了。后来找到这样的原因。打个比方,2000年是闰年,2000年2月以前的日期到后一年同一天的日期相差366天,1999年3月份以后的日期到后一年同一天的日期相差也是366天。但我一开始写的是如果这一年是闰年那到后一年同一天的日期是366天,这其中出现bug,比如2000年3月份到后一年同一天的日期相差只有365天。后来我更改之后的代码如下:
public DateUtil getNextNDays(int n){ int d=this.getDay().getValue(); int m=this.getMonth().getValue(); int y= this.getYear().getValue(); DateUtil dateUtil=new DateUtil(d,m,y); while(n>0) { if (n >= 366) { if (dateUtil.month.value<=2&&dateUtil.getYear().isLeapYear()) { dateUtil.year.value = dateUtil.year.getValue() + 1; dateUtil.month.value = dateUtil.month.getValue(); dateUtil.day.Value = dateUtil.day.getValue(); n = n - 366; } else if (dateUtil.month.value>2&&((dateUtil.getYear().getValue()+1) % 4 == 0 && (dateUtil.getYear().getValue()+1) % 100 != 0) || (dateUtil.getYear().getValue()+1) % 400 == 0){ dateUtil.year.value++; dateUtil.month.value = dateUtil.month.getValue(); dateUtil.day.Value = dateUtil.day.getValue(); n = n - 366; } else{ dateUtil.year.value = dateUtil.year.value + 1; dateUtil.month.value = dateUtil.month.getValue(); dateUtil.day.Value = dateUtil.day.getValue(); n = n - 365; } } if (n < 366 && n >= 31) { if (dateUtil.year.isLeapYear() && dateUtil.month.getValue() == 2) { dateUtil.month.value = dateUtil.month.getValue() + 1; dateUtil.day.Value = dateUtil.day.getValue(); n = n - 29; } else{ n = n - mon_maxnum[dateUtil.month.getValue()-1]; if(dateUtil.month.value==12){ dateUtil.year.value++; dateUtil.month.resetMin(); }else { dateUtil.month.value = dateUtil.month.getValue() + 1; } dateUtil.day.Value = dateUtil.day.getValue(); } } if (n < 31 && n > 0) { if (dateUtil.day.getValue() + n >= mon_maxnum[dateUtil.month.getValue()-1]) { if(dateUtil.year.isLeapYear()&&dateUtil.month.getValue()==2&&dateUtil.day.getValue()+n==29){ dateUtil.day.Value=29; }else if(dateUtil.year.isLeapYear()&&dateUtil.month.getValue()==2&&dateUtil.day.getValue()+n!=29) { dateUtil.day.Value=dateUtil.day.getValue()+n-29; dateUtil.month.value++; }else { if(dateUtil.month.value==12){ dateUtil.year.value++; dateUtil.month.resetMin(); dateUtil.day.Value=dateUtil.day.getValue()+n-mon_maxnum[11]; }else { dateUtil.month.value = dateUtil.month.getValue() + 1; dateUtil.day.Value = dateUtil.day.getValue() + n - mon_maxnum[dateUtil.month.getValue()-2]; } } } else{ dateUtil.day.Value=dateUtil.day.getValue()+n; } n=0; } } return dateUtil; }
运行结果如下:

改进意见
我主要的意见还是对于类似于继承、接口这样的知识点新出现时设置的题目可以让这些知识点更有存在意义和价值,而不是走个形式加一个无意义的点进去表示我在考你这个知识点而已。
总结
这几次题目集的难度和题量都在线,也学到了不少东西,继承、多态、接口、集合框架的应用,做题也更利于我去掌握这些知识点,但是自己投入时间不够导致很多题都是在提交之后考试结束之后做出......也没能去通过PTA测试看看有没有遗漏的测试点没过,总之对于自己就是要求加大投入时间提高工作效率。

浙公网安备 33010602011771号