0.前言
在第一作业周期内,通过PTA上前三次作业和MOOC作业上的练习,对于JAVA这门程序语言有了初步的认识,也能利用JAVA语法进行一些简单的编程。在这些作业中,大致能够通过已经掌握的知识完成题目所要求的功能,但仍然存在编程思想的问题。比如第一时间的解决思路总是会用面向过程来实现,一些常见操作也会将C语言语法转化为JAVA语法来实现。与此对应的便是对面向对象的思想还不够深刻,类、方法和对象之间的灵活运用还有待加强。
1.作业过程总结
①三次作业之间的知识迭代关系:
第一次作业主要是使用具体的单一方法实现某个简单问题,第二次作业开始需要多个方法实现较繁琐的问题,第三次作业开始需要根据题目要求使用所给的类的定义来进行繁琐的代码设计,涉及到方法和对象的大量使用。
②如何通过作业逐步从面向过程过渡到面向对象
在面向过程编程时,需要根据问题来思考怎么样一步一步地实现,相对符合正常解决问题的逻辑。而在面向对象编程时,首先需要根据问题进行类的设置,然后再确定属性和方法,接着再确定具体的对象并在测试类中来解决问题。通过三次的作业,第一次是学会利用JAVA语法解决某个简单问题,做到对JAVA运行环境的熟悉,并能掌握程序的调试方法;第二次是学会设计多个方法解决较复杂问题,能够对方法有清楚的理解,在此基础上还要考虑对象的引入,所有方法的使用都需要对象来完成。第三次是学会设计多个类解决复杂问题,同时对于相同的问题能够根据需求设计不同的类方案。在这一次作业中,需要宏观地考虑整体不同类之间的关系,理解类的属性和方法以及对象的使用,细节之中也要顾及到属性的公开或隐私。通过第三次作业可以完全地从根本的编程思想将原来的面向过程过渡到面向对象,从需求的最初的上手解决就必须从面向对象出发。
③作业过程中遇到的问题及解决方法(红色倾斜字体为部分解决方法的代码)
初次学习新的一门编程语言,也是一门从编程思想上与C语言有着根本不同的编程语言,作业过程中会遇到非常多的问题,从第一次作业到第三次作业,问题可以小到语法问题,也可以大到类和方法的设计问题。
具体的有,(1)第一次作业需要输入参数的问题,在C语言中可以直接使用scanf语句进行参数输入,而在JAVA中需要先声明Scanner input = new Scanner(System.in);和import java.util.Scanner;然后再对具体参数进行赋值。此外,(2)第一次作业的7-5题,需要使用到JAVA中特有的数组类使用方法——add和get方法,可以大大提高解决效率,解决问题相比较C语言快捷方便。还有的问题就是具体的某个问题的解决方案,(3)比如7-4题判断三角形类型中的判断等腰直角三角形。根据等腰直角三角形的特殊性,必有一边或两边是无理数,如果使用a^2+b^2=c^2和a==b的判别条件来判断是否为等腰直角三角形会因为数据精度问题而出现差错,可以通过确定精度来判断是否为等腰直角三角形,我使用的是if((((Math.abs(c*c-a*a-b*b)<1e-5)||(Math.abs(b*b-a*a-c*c)<1e-5)||(Math.abs(a*a-b*b-c*c)<1e-5)))&&(a==b||a==c||b==c))。
(4)第二次作业中的问题主要是7-1中的保留四位小数。通过查阅网络信息,我的解决方案是使用DecimalFormat类,对输出的两个实数解进行格式化,打印语句是System.out.println("The equation has two roots: "+df.format(x1)+" and "+df.format(x2));但是使用这一方法保留小数时,PTA有一项测试点不能通过,经测试是当实数解为0时,程序运行结果格式为.0000而不是要求的0.0000。这时,我设置了一个if语句来判断实数解是否为0来决定输出的格式。之后的7-2,7-3,7-4题都是需要找准实现的思路,以及仔细考虑边界问题就基本可以实现题目要求。
(5)第三次作业中的问题主要是根据同一问题要设计不同的类的实现方案,在敲代码之前要事先在定好一个代码框架来梳理不同类之间的关系,根据不同的类的关系来分别设计不同的解决方法。再具体一些就是在实现某些功能时的问题,比如在实现求后N天功能时,PTA的一个边界测试点不能通过,进过排查是数据超过了int的最大限制,我的解决方法是设置中间变量,然后进行long和int的强制类型转换,解决得比较直接粗暴,有待更佳的解决方案。以下是具体的实现细节:
1 public DateUtil getNextNDays(int n) { 2 int check,temp; 3 if(isLeapYear(year)) 4 check = 0; 5 else 6 check = 1; 7 long n1 = (long)n; 8 long day1 = (long)day; 9 long day2=(long)(day1+n1); 10 11 12 temp=month; 13 for( ;day2>a[check][temp-1];temp++) 14 { 15 day2=day2-a[check][temp-1]; 16 if(temp==12) 17 { 18 temp=0; 19 year++; 20 } 21 if(isLeapYear(year)) 22 check = 0; 23 else 24 check = 1; 25 } 26 month=temp; 27 day = (int)day2; 28 return new DateUtil(year,month,day); 29 30 }
④每次作业花费的时间比例
没有经过比较严谨的时间记录,大致是1:1:3,第一次作业熟悉JAVA语法和运行环境花费了比较多的时间,第二次作业有了大致的解决思路在第一次作业的基础上写得相对轻松一点,第三次作业需要考虑很多类、方法和对象的问题花费了最多的时间。
⑤对编程过程严谨性的认识和教训
在编程过程中,由于JAVA的编译的机制可以及时发现语法问题,可以避免低级的语法错误。除此之外,编程过程中主要有对象的正确使用问题,经常会因为空指针而导致对象出错。其余方面有数据边界问题和输入非法问题的判断和解决。在编程中都应该尽量事先考虑到以上问题,避免之后再回过来一个一个地寻找错误,效率较低。
2.OO设计心得
①面向过程与面向对象的比较
在面向过程编程时,需要根据问题来思考怎么样一步一步地实现,相对符合正常解决问题的逻辑。而在面向对象编程时,首先需要根据问题进行类的设置,然后再确定属性和方法,接着再确定具体的对象并在测试类中来解决问题。类似的大致对比可参加以下对比:
问题:根据圆的半径和圆柱的切面圆半径和高分别求圆的周长和面积以及圆柱的表面积和体积
1 import java.util.Scanner; 2 public class MathString { 3 Circle circle=new Circle(); 4 Cylinder cylinder=new Cylinder(); 5 public static void main(String[] args) { 6 Scanner input = new Scanner(System.in); 7 System.out.println("请输入圆的半径:"); 8 MathString m = new MathString(); 9 String r1 = input.nextLine(); 10 m.circle.r = Integer.parseInt(r1); 11 System.out.println("该圆的周长:"+m.circle.circu(m.circle.r)); 12 System.out.println("该圆的面积:"+m.circle.area(m.circle.r)); 13 System.out.println("请输入圆柱体的高和切面半径:"); 14 String r2 = input.nextLine();String h = input.nextLine(); 15 m.cylinder.r = Integer.parseInt(r2); 16 m.cylinder.h = Integer.parseInt(h); 17 System.out.println("该圆柱体的表面积: "+m.cylinder.sarea(m.cylinder.r,m.cylinder.h)); 18 System.out.println("该圆柱体的体积: "+m.cylinder.vol(m.cylinder.r,m.cylinder.h)); 19 } 20 class Circle{ 21 int r; 22 public double area(int r){ 23 double s = Math.PI*Math.pow(r, 2);return s; 24 } 25 public double circu(int r) { 26 double c = 2*Math.PI*r;return c; 27 } 28 } 29 class Cylinder{ 30 int r;int h; 31 public double sarea(int r,int h) { 32 double sa = 2*Math.PI*Math.pow(r, 2)+2*Math.PI*r*h;return sa; 33 } 34 public double vol(int r,int h) { 35 double v = Math.PI*Math.pow(r, 2)*h;return v; 36 } 37 } 38 }
1 import java.util.Scanner; 2 3 public class Circle { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 String r,r1; 8 String h; 9 Scanner input = new Scanner(System.in); 10 System.out.println("请输入圆的半径:"); 11 r = input.nextLine(); 12 System.out.println("该圆的周长:"+2*Math.PI*Integer.parseInt(r)); 13 System.out.println("该圆的面积:"+Math.PI*Math.pow(Integer.parseInt(r),2)); 14 15 System.out.println("请输入圆柱体的高和切面半径:"); 16 h = input.nextLine(); 17 r1 = input.nextLine(); 18 double s = 2*Math.PI*Math.pow(Integer.parseInt(r1),2)+2*Math.PI*Integer.parseInt(r1)*Integer.parseInt(h); 19 System.out.println("该圆柱体的表面积: "+s); 20 System.out.println("该圆柱体的体积: "+Math.PI*Math.pow(Integer.parseInt(r1),2)*Integer.parseInt(h)); 21 } 22 23 }
②面向对象设计的基本原则理解
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
③OO编程思维的理解
OO是把问题中的内容经过抽象分析,在软件的世界中创造与之对应的对象,这样在思考问题的解决时,更符合人对世界的认识思维模式,毕竟人在现实世界中碰到的问题、思考的问题形成的思维模式更易于理解并具有普遍性。
3.测试的理解与实践
①测试对于编码质量的重要性
通过测试可以对编码的各个功能的完成度有一个清楚直接的认知,利用Junit 4 Assert @Tset能一个一个比对测试用例的要求值和实际值。测试反映编码功能是否完备的同时,还反映编码的效率,比如编码的占用内存和运行时间。如果能设计好测试用例,可以对编码质量有全面的评估。
②假如让你设计测试用例,你会如何做
设计测试用例可以以测试编码的极限和边界情况、输入输出的格式、运行的时间、编码占用的内存等等目的出发。具体可以设置一些参数使编码能运行到数据类型的边界值,或者是使编码运行最长时间、占用最多的内存......
4.课程收获
通过四周的学习和练习,对JAVA有了初步的入门,对OO也有了一定的理解。对于OO,我获得的收获就是面对问题不能只从问题的表面来思考便直接进行解决,而是挖掘问题本身的属性,从根本的属性设计不同的方法,然后再代入问题进行实际解决。
5.对课程的建议
老师可以将课上的一些代码样例上传到群文件,然后能对课程进行录像,可以方便课后更好更快的实践作业,之前课后都因为代码截图不及和课后回放上传较慢不方便做作业时回顾。
6.之后一阶段的学习计划
之后一阶段仍然要加强OO编程思维的练习,面对问题要考虑分不同的类和对象。