Java面向对象程序设计第一次博客作业
【针对前三次PTA题目集】
一、前言
(1).知识点:
在我看来,这三次题目集的知识点主要有:1.类的声明和定义,即根据题目可以写出一个类,且类中的变量和方法都要与此类相关,要有总结归纳能力;
2.实例方法和成员变量的调用,即类中定义的实例方法和非static变量不可以直接调用,要通过类的对象来调用;
3.对String类中的方法的使用:通过调用String类的一些方法,可以使代码更加简洁,减少工作量,例如获取子字符串,查找 字符串等等;
(2).题量与难度:
我认为7-1题目集的题量偏大,但是整体来说都比较简单,每次写完一题也不需要花费很长时间;
7-2题目集的题量不多,但是整体难度相对于7-1都提升了,每一题的要求也更多,很多时候不是编译错误而是逻辑错误或者没有实现题目的某个要求,要用更多时间调试。
7-3题目集的题量也不多,但是我认为真的很难。7-3的题目基本上都是数学题,但是需要我们用代码解答,这不仅要我们想出算法,还要让这个算法能够实现,给出正确的结果。
二.设计与分析
【对题目集二的7-2分析】
本题是实现串口字符串的解析。首先我自定义了一个类,其中的成员变量private String serialCh用来储存用户输入的字符串,一个带参的构造器,以及两个方法用来解析字符串。
1.方法 public boolean nullData()是用来数据是否不足11位或者输入数据全1没有起始位。这个方法的实现比较简单,只需要得出字符串的长度以及第一个字符是否为‘1’就可以了。
2.方法 public void outputResult()是用来输出判断结果的。因为输入字符串的长度不确定,所以我写了一个for循环,而由于变量i的赋值语句稍显复杂,我就在循环体中对i赋值,并且写if()语句判断是否退出循环。我的解析思路是:找到字符0后,跳过字符0后的八个有效数字,对后两位分别进行奇校验,即判断该字符是否为‘1’和结束位检验,即判断该字符是否为‘1’。所以题目虽然看上去比较复杂,但实际在写代码的过程中还是比较容易实现题目的要求的。
源码如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { //System.out.println("请输入数据: "); Scanner input = new Scanner(System.in); Serial s = new Serial(input.next()); if(s.nullData()){ s.outputResult(); }else{ System.out.print("null data"); } } } class Serial { private String serialCh = "11111111";//串口字符 public Serial(String serialCh){ this.serialCh = serialCh; } public String getSerialCh(){ return serialCh; } //判断数据是否不足11位或者输入数据全1没有起始位 public boolean nullData(){ if(serialCh.length() >= 11 && serialCh.indexOf('0') != -1){ return true; }else{ return false; } } //输出结果 public void outputResult() { int count = 1; int i = 0; for (; ; ) { while(i < serialCh.length()){ if(serialCh.charAt(i) == '0'){ break; } i++; } i += 10; if(i < serialCh.length()){ if (serialCh.charAt(i - 1) == '1' && serialCh.charAt(i) == '1') { System.out.print(count++ + ":" + serialCh.substring(i - 9, i - 1) + "\n"); } else if (serialCh.charAt(i) == '1') { System.out.print(count++ + ":parity check error\n"); } else { System.out.print(count++ + ":validate error\n"); } }else{ break; } } } }
【对题目集3的7-1的的分析】
本题是计算两点之间的距离,光看题目感觉还挺简单,事实证明我想多了。我认为实现计算两点的距离是比较容易的,难点在于判断用户输入的坐标格式是否正确,以及对输入的坐标是否合法。因此我的代码大部分都是对输入的检验。
首先,以字符串的形式接收用户输入的数据,并且要拆分字符串以便判断,这里用到了String类中的spilt()函数。拆到最后既可以得到横纵坐标,也就是浮点数。并创建两个Point对象,相当于储存了两个坐标的数据。并且我在自定义的Point类中写了计算距离方法,一行代码就可以搞定。其次,通过两个静态方法判断输入数据是否合法,若 合法就计算距离。不合法输出相应语句。
1.静态方法 public static boolean isTwoPoint(String point):用来判断输入的坐标是否为两个。我是根据空格的位置判断的,因为如果只有一个空格,那么不论是从前往后找,还是从后往前找,返回的下标都是同一个,若有两个及以上的空格,那么返回的下标就不相等了,即输入的坐标不是两个。这里我用到了lastIndexof()和indexof()返回空格的下标。
2. public static boolean isValid(String point):判断输入数据是否合法。我的思路是如果这个数字的前两个字符都是+或-,那么就是不合法的,实现起来也比较容易。
源码如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); //System.out.println("请输入两个点的坐标(两个坐标之间以空格分隔):");
String points = input.nextLine(); if(isTwoPoint(points)){ String[] point = points.split("\\s");//以空格拆分字符 String[] point1 = point[0].split(","); String[] point2 = point[1].split(","); if(isValid(point1[0]) && isValid(point1[1]) && isValid(point2[0]) && isValid(point2[1])){ Point p1 = new Point(); Point p2 = new Point(); p1.setX(Double.parseDouble(point1[0])); p1.setY(Double.parseDouble(point1[1])); p2.setX(Double.parseDouble(point2[0])); p2.setY(Double.parseDouble(point2[1])); System.out.println(p1.distanceOfTwoPoints(p2)); }else{ System.out.println("Wrong Format"); } } } //判断输入的坐标是否为两个 public static boolean isTwoPoint(String point){ if(point.lastIndexOf(" ") != point.indexOf(" ")){ System.out.println("wrong number of points"); return false; } return true; } public static boolean isValid(String point){ if(point.length() > 2) { char i = point.charAt(0); char j = point.charAt(1); if ((i == '-' || i == '+') && (j == '-' || j == '+')) { return false; } } return true; } } class Point { private double x;//横坐标 private double y;//纵坐标 public Point(){ } public double distanceOfTwoPoints(Point point){ return Math.sqrt((this.x - point.x) * (this.x - point.x) + (this.y - point.y) * (this.y - point.y)); } public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } public static void main(String[] args) { Point point1 = new Point(); point1.setX(+2); point1.setY(-2.3); Point point2 = new Point(); point2.setX(0.9); point2.setY(-3.2); System.out.println(point1.distanceOfTwoPoints(point2)); } }
【对题目集3的7-2的分析】
这一题简直就是我噩梦的开始
本题是要求实现有关线的计算。我认为前四个要求实现起来不是特别难,第五个要求和对输入数据的合法校验实现起来比较困难。
并且在本题中我没有写自定义类,因为题目的要求虽然多,但是它们之间基本找不出什么共同特征,真要自定义类就只能写Point的这种,但是没有什么作用,因为题目是有关线的计算,在Point类中不好实现。所以我在主类中定义了很多的静态方法,写着写着就觉得自己在写c语言。
用户输入数据,首先要判断数据的合法性,题目给出了判断的输入基本格式。一开始我是想着有没有方法可以直接判断输入数据是否符合基本格式的,在网上一查还真有,叫正则表达式,但是我看不太懂,还是放弃了,乖乖自己想办法吧。后来我就用了一个比较取巧的方法,不管输入了几个坐标,我只判断第二个字符是不是冒号,逗号前面是不是0-9的字符。这种写法显然有很大的漏洞,比如前两个坐标是合法的,但第三个是非法的,那么我写的代码就判断不出来了。
检验完数据的合法性之后,就开始实现对应的功能了。我认为前四个功能实现起来都不是很难,因为基本上根据数学公式就可以把代码写出来,有点像把在纸上的计算过程移植到了代码中。
但是第五个功能,也就是计算并判断交点坐标,看的我真的是一头雾水,我还特意去网上查了相关资料,看看有没有什么数学公式能够让我可以用面向对象的预言实现的,然后真的就找到了一个公式,它是直接根据四个坐标进行一些列四则运算得到的。
所以7-2虽然写起来很痛苦,但是还是把它写完了。
源码如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); //System.out.println("enter data: "); String data = input.nextLine(); String[] points = data.split("\\s");//根据空格拆分字符 if (points[0].charAt(1) != ':') {//判断输入的数据是否符合基本输入格式 System.out.println("Wrong Format"); return; } else { for (int i = 1; i < points.length; i++) { int posNum = points[i].indexOf(','); posNum--; if (points[i].charAt(posNum) < '0' || points[i].charAt(posNum) > '9') { System.out.println("Wrong Format"); return; } } } char option = points[0].charAt(0); switch(option){ case '1':{ if(points.length != 2){//若数组长度不等于2,则输入的坐标数量有问题 System.out.println("wrong number of points"); return; }else{ double[] xy = new double[4]; spilt(xy,points); if(!coincide(points, option)){ System.out.println("points coincide"); return; }else { if (xy[0] == xy[2]) { System.out.println("Slope does not exist"); } else { System.out.println((xy[1] - xy[3]) / (xy[0] - xy[2])); } } } break; } case '2':{ if(points.length != 3){ System.out.println("wrong number of points"); return; }else{ double[] xy = new double[6]; spilt(xy, points); if(!coincide(points, option)){ System.out.println("points coincide"); return; } System.out.println(distance(xy)); } break; }case '3':{ if(points.length != 3){ System.out.println("wrong number of points"); return; }else{ double[] xy = new double[6]; spilt(xy, points); if(!coincide(points, option)){ System.out.println("points coincide"); return; } System.out.println(oneLine(xy)); } break; }case '4':{ if(points.length != 4){ System.out.println("wrong number of points"); return; }else{ double[] xy = new double[8]; spilt(xy, points); if(!coincide(points, option)){ System.out.println("points coincide"); return; } System.out.println(parallel(xy)); } break; }case '5':{ if(points.length != 4){ System.out.println("wrong number of points"); return; }else{ double[] xy = new double[8]; spilt(xy, points); if(!coincide(points, option)){ System.out.println("points coincide"); return; } boolean isParallel = parallel(xy); if(isParallel){ System.out.println("is parallel lines,have no intersection point"); }else{ double denominator = (xy[3] - xy[1])*(xy[6] - xy[4]) - (xy[0] - xy[2])*(xy[5] - xy[7]); double x = ( (xy[2] - xy[0]) * (xy[6] - xy[4]) * (xy[5] - xy[1]) + (xy[3] - xy[1]) * (xy[6] - xy[4]) * xy[0] - (xy[7] - xy[5]) * (xy[2] - xy[0]) * xy[4]) / denominator ; double y = -( (xy[3] - xy[1]) * (xy[7] - xy[5]) * (xy[4] - xy[0]) + (xy[2] - xy[0]) * (xy[7] - xy[5]) * xy[1] - (xy[6] - xy[4]) * (xy[3] - xy[1]) * xy[5] ) / denominator; String s = x + "," + y; if( (x - xy[0]) * (x - xy[2]) <= 0 && (y - xy[1]) * (y - xy[3]) <= 0 && (x - xy[4]) * (x - xy[6]) <= 0 && (y - xy[5]) * (y - xy[7]) <= 0 ){ System.out.println(s + " " + true); }else{ System.out.println(s + " " + false); } } } break; } } }
//判断输入的点是否在一条线上 public static boolean oneLine(double[] xy){ double ab = Math.sqrt((xy[0] - xy[2]) * (xy[0] - xy[2]) + (xy[1] - xy[3]) * (xy[1] - xy[3])); double bc = Math.sqrt((xy[2] - xy[4]) * (xy[2] - xy[4]) + (xy[3] - xy[5]) * (xy[3] - xy[5])); double ac = Math.sqrt((xy[0] - xy[4]) * (xy[0] - xy[4]) + (xy[1] - xy[5]) * (xy[1] - xy[5])); return ac == ab + bc || ac == Math.abs(ab - bc); }
//计算点到直线的距离 public static double distance(double[] xy){ if(xy[2] == xy[4]){ return (Math.abs(xy[0] - xy[2])); }else if(xy[3] == xy[5]){ return (Math.abs(xy[1] - xy[3])); }else{ double k = (xy[3] - xy[5]) / (xy[2] - xy[4]); return (Math.abs(k * xy[0] - xy[1] + xy[3] - k * xy[2])) / Math.sqrt(k * k + 1); } }
//判断直线是否平行 public static boolean parallel(double[] xy){ boolean isSlope1 = true; boolean isSlope2 = true; if (xy[0] == xy[2]) {//若横坐标想等,则平行 isSlope1 = false; } if(xy[4] == xy[6]){ isSlope2 = false; } if(!isSlope1 && !isSlope2){ return true; }else if(isSlope1 && isSlope2){//根据斜率判断 double k1 = (xy[1] - xy[3]) / (xy[0] - xy[2]); double k2 = (xy[5] - xy[7]) / (xy[4] - xy[6]); return k1 == k2; }else{ return false; } }
//拆分字符串,得到浮点数 public static void spilt(double[] xy, String[] points){ String[] s1 = points[0].split(","); String[] s2 = s1[0].split(":"); xy[0] = Double.parseDouble(s2[1]); xy[1] = Double.parseDouble(s1[1]); for(int i = 1; i < points.length; i++){ String[] s = points[i].split(","); int j = 2 * i; xy[j] = Double.parseDouble(s[0]); xy[j + 1] = Double.parseDouble(s[1]); } }
//判断输入的点是否重合 public static boolean coincide(String[] points, char option) { String point = points[0].substring(2); if (option == '1') { return !point.equals(points[1]); } else if (option == '2' || option == '3') { return !point.equals(points[1]) && !point.equals(points[2]) && !points[1].equals(points[2]); } else { return !point.equals(points[1]) && !point.equals(points[2]) && !point.equals(points[3]) && !points[1].equals(points[2]) && !points[1].equals(points[3]) && !points[2].equals(points[3]); } } }
【题目集3的7-3分析】
本题是实现对三角形的计算。我认为其中的大部分要求都是很好实现的,比如判断角的类型,计算面积周长、判断三角形类型等等,因为数学公式简单,所以用代码实现起来也很简单。并且有了上一题的经验,在校验输入数据是否合法这一块也写得更加顺手了,依旧是通过切割字符串来进行判断,不得不说spilt()方法是真的好用。
非常让我头疼的是输出前两个点所在的直线与三个点所构成的三角形相交的交点数量以及面积,思来想去很久,我也想不出来有什么办法可以实现这个功能,我也查过资料,但都不适用,所以我在这块只是进行了基础的数据校验,没有实现功能的代码。最后一个用射线法判断点是否在三角形内部的要求,虽然是第一次见,但好在可以在网上查阅到相关资料,即射线法的使用。为此我是使用了Point2D类进行操作,我也是看了射线法的讲解才想起坐标也可以直接用Point2D.Double(x, y)表示,这样一来代码可以简洁不少。射线法的原理大致是这样:从这个点做一条射线,计算它跟多边形边界的交点个数,如果交点个数为奇数,那么点在多边形内部,否则点在多边形外。并且如果点在多边形内部,射线第一次穿越边界一定是穿出多边形。如果点在多边形外部,射线第一次穿越边界一定是进入多边形。有了解题思路,第五个功能也就得以实现。
源码如下:
import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); //System.out.println("enter data: "); String data = input.nextLine(); String[] points = data.split("\\s"); if (points[0].charAt(1) != ':') { System.out.println("Wrong Format"); return; } else { for (int i = 1; i < points.length; i++) { int posNum = points[i].indexOf(','); posNum--; if (points[i].charAt(posNum) < '0' || points[i].charAt(posNum) > '9') { System.out.println("Wrong Format"); return; } } } char option = points[0].charAt(0); switch(option) { case '1': { if (points.length != 3) { System.out.println("wrong number of points"); return; } else { double[] xy = new double[6]; spilt(xy, points); double[] abc = new double[3];//三条边 threeSides(xy, abc, option); if(!isTriangle(abc)){ System.out.println("data error"); }else{ if(isosceles(abc)){ System.out.println("true " + (abc[0] == abc[1] && abc[0] == abc[2])); }else{ System.out.println("false false"); } } } break; } case '2': { if (points.length != 3) { System.out.println("wrong number of points"); return; } else { double[] xy = new double[6]; spilt(xy, points); double[] abc = new double[3];//三条边 threeSides(xy, abc, option); if(!isTriangle(abc)){ System.out.println("data error"); }else{ double c = abc[0] + abc[1] + abc[2]; c = (int)(c * 1E6 + 0.5) / 1E6; double s = area(xy); s = (int)(s * 1E6 + 0.5) / 1E6; double x = (xy[0] + xy[2] + xy[4]) / 3; x = (int)(x * 1E6 + 0.5) / 1E6; double y = (xy[1] + xy[3] + xy[5]) / 3; y = (int)(y * 1E6 + 0.5) / 1E6; System.out.println(c + " " + s + " " + x + "," + y); } } break; } case '3': { if (points.length != 3) { System.out.println("wrong number of points"); return; } else { double[] xy = new double[6]; spilt(xy, points); double[] abc = new double[3];//三条边 threeSides(xy, abc, option); if(!isTriangle(abc)){ System.out.println("data error"); }else{ int type = judgeType(abc); if(type == 1){ System.out.println("true false false"); }else if(type == 2){ System.out.println("false true false"); }else{ System.out.println("false false true"); } } } break; } case '4': { if (points.length != 5) { System.out.println("wrong number of points"); return; } else { double[] xy = new double[10]; spilt(xy, points); if(xy[0] == xy[2] && xy[1] == xy[3]){ System.out.println("points coincide"); return; } double[] abc = new double[3];//三条边 threeSides(xy, abc, option); if(!isTriangle(abc)){ System.out.println("data error"); }else{ System.out.println("The point is on the edge of the triangle"); } } break; } case '5': { if (points.length != 4) { System.out.println("wrong number of points"); } else { double[] xy = new double[8]; spilt(xy, points); Point2D.Double d = new Point2D.Double(xy[0], xy[1]); List<Point2D.Double> pointList = new ArrayList<>(); pointList.add(new Point2D.Double(xy[2], xy[3])); pointList.add(new Point2D.Double(xy[4], xy[5])); pointList.add(new Point2D.Double(xy[6], xy[7])); double[] abc = new double[3];//三条边 threeSides(xy, abc, option); if(!isTriangle(abc)){ System.out.println("data error"); }else{ isInArea(pointList, d); } break; } } } } public static int judgeType(double[] abc){ double a = abc[0] * abc[0]; double b = abc[1] * abc[1]; double c = abc[2] * abc[2]; if((a > b + c) || (b > a + c) || (c > a + b)){ return 1; }else if(a == b + c || b == a + c || c == b + a){ return 2; }else{ return 3; } } public static void isInArea(List<Point2D.Double> pointList, Point2D.Double point) { Boolean flag = true; Point2D.Double p, p1, p2; int across = 0; double precision = 2e-10; p = point; for (int i = 0; i < pointList.size(); i++) { p1 = pointList.get(i); int j = (i + 1) >= pointList.size() ? 0 : (i + 1); p2 = pointList.get(j); if (p1.equals(p) || p2.equals(p)) { System.out.println("on the triangle"); return ; } if (p.y <= Math.max(p1.y, p2.y) && p.y >= Math.min(p1.y, p2.y)) { if (p.x <= Math.max(p1.x, p2.x) && p.x >= Math.min(p1.x, p2.x)) { if (p1.y == p2.y) { if (p.y == p1.y) { System.out.println("on the triangle"); return; } } if (p1.x == p2.x) { if (p.x == p1.x) { System.out.println("on the triangle"); return; } } double xSY = p1.y + (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x); if (Math.abs(xSY - p.y) < precision) { System.out.println("on the triangle"); return; } } if (p.x <= Math.min(p1.x, p2.x)) { continue; } if (p1.y != p2.y && p.y != Math.min(p1.y, p2.y)) { across++; } } } if (across % 2 == 0) { System.out.println("outof the triangle"); return; } System.out.println("in the triangle"); } public static double area(double[] xy){ return Math.abs(xy[0] * (xy[3] * xy[5]) + xy[2] * (xy[5] - xy[1]) + xy[4] * (xy[1] - xy[3])) / 2; } public static boolean isosceles(double[] abc){ return abc[0] == abc[1] || abc[0] == abc[2] || abc[1] == abc[2]; } public static void threeSides(double[] xy, double[] abc, char option){ if(option == '4'){ abc[0] = Math.sqrt((xy[4] - xy[6]) * (xy[4] - xy[6]) + (xy[5] - xy[7]) * (xy[5] - xy[7])); abc[1] = Math.sqrt((xy[4] - xy[8]) * (xy[4] - xy[8]) + (xy[5] - xy[9]) * (xy[5] - xy[9])); abc[2] = Math.sqrt((xy[6] - xy[8]) * (xy[6] - xy[8]) + (xy[7] - xy[9]) * (xy[7] - xy[9])); }else if(option == '5'){ abc[0] = Math.sqrt((xy[4] - xy[6]) * (xy[4] - xy[6]) + (xy[5] - xy[7]) * (xy[5] - xy[7])); abc[1] = Math.sqrt((xy[2] - xy[6]) * (xy[2] - xy[6]) + (xy[3] - xy[7]) * (xy[3] - xy[7])); abc[2] = Math.sqrt((xy[2] - xy[4]) * (xy[2] - xy[4]) + (xy[3] - xy[5]) * (xy[3] - xy[5])); }else{ abc[0] = Math.sqrt((xy[0] - xy[2]) * (xy[0] - xy[2]) + (xy[1] - xy[3]) * (xy[1] - xy[3])); abc[1] = Math.sqrt((xy[0] - xy[4]) * (xy[0] - xy[4]) + (xy[1] - xy[5]) * (xy[1] - xy[5])); abc[2] = Math.sqrt((xy[2] - xy[4]) * (xy[2] - xy[4]) + (xy[3] - xy[5]) * (xy[3] - xy[5])); } } public static boolean isTriangle(double[] abc){ return ((abc[0] + abc[1] > abc[2]) && (abc[0] + abc[2] > abc[1]) && (abc[1] + abc[2] > abc[0])); } public static void spilt(double[] xy, String[] points){ String[] s1 = points[0].split(","); String[] s2 = s1[0].split(":"); xy[0] = Double.parseDouble(s2[1]); xy[1] = Double.parseDouble(s1[1]); for(int i = 1; i < points.length; i++){ String[] s = points[i].split(","); int j = 2 * i; xy[j] = Double.parseDouble(s[0]); xy[j + 1] = Double.parseDouble(s[1]); } } }
(3)采坑心得:
1.使用数组一定要注意数组的范围,特别是在边界,比如在串口字符串解析中,我的代码就出现了数组越界,调试起来也挺麻烦的
2.看清楚题目要我们输出的内容,最好是直接从“输出格式”那里复制粘贴,自己打的话有一定风险,而且这种错误我认为是很难检查出来的,特别是输出的格式很多的时候
3.如果调用的不是自己写的方法,那么要弄清你调用的方法的形参是什么,返回值是什么,这样在调用的时候才不会出错。
(4)改进建议:
降低代码的耦合度,做到低耦合高内聚。我在第三个题目集中基本没有使用自定义类,虽然方法和方法之间的耦合度不是很高,但是我还是希望可以通过更多的实例方法实现题目要求而不是静态方法,否则感觉自己在写C语言。
(5)总结:对本阶段三次题目集的综合性总结,学到了什么,哪些地方需要进一步学习及研究,对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见。
对于本阶段三次题目集的练习,我能熟练运用一些String类中的方法,比如字符串的切割方法,spilt();查找字符的方法,indexof()、lastIndexof();我也对实例方法和静态方法的区别有了更深入的了解-----实例方法必须通过对象调用,同时实例方法可以调用静态方法,而静态方法可以直接通过类名调用,不用创建对象,并且静态方法不可以调用实例方法。
改进建议:我希望pta作业的难度不要太大,可以和实验的难度的差不多。
本次的分析到此结束~

浙公网安备 33010602011771号