前言:

  这三周的Java课程主要学习了Collections接口的很多实现。了解了一些基本数据类型并可以做一些简单的运用。在这三周的题目量并不多,但是题目难度有所提升。PTA中的题目集很难像以前那样拿到满分。并且每次都会对题目进行迭代,无形中迫使我们需要认真设计类,才能完成后续迭代的需求,加强了对OOP的运用和理解。


设计与分析:

 PTA图形类设计:

   题目描述:

面向对象程序设计第二单元总结-LMLPHP

   类图:没有进行类的设计。

   源码:

  1 import java.util.Scanner;
  2 
  3 public class Main {
  4     public static void main(String[] args) {
  5         Scanner in = new Scanner(System.in);
  6         String line = in.nextLine();
  7         try {
  8             int coi = Integer.parseInt(line.substring(0, 1));
  9             if (coi < 1 || coi > 5) {
 10                 System.out.print("Wrong Format");
 11                 System.exit(0);
 12             }
 13             switch (coi) {
 14                 case 1:
 15                     System.out.print(calculateSlope(line.substring(2)));
 16                     break;
 17                 case 2:
 18                     System.out.print(calculateDistance(line.substring(2)));
 19                     break;
 20                 case 3:
 21                     System.out.print(isColinear(line.substring(2)));
 22                     break;
 23                 case 4:
 24                     System.out.print(isParallel(line.substring(2)));
 25                     break;
 26                 case 5:
 27                     System.out.print(isIntersectWithinSegment(line.substring(2)));
 28                     break;
 29             }
 30         } catch (Exception e) {
 31             System.out.print("Wrong Format");
 32             System.exit(0);
 33         }
 34     }
 35 
 36     /**
 37      * 计算两点构成线段的斜率
 38      */
 39     public static double calculateSlope(String data) {
 40         String[] points = data.split(" ");
 41 
 42         String point1 = points[0], point2 = points[1];
 43         double x1 = 0, y1 = 0;
 44         double[] xy = processData(point1);
 45         x1 = xy[0];
 46         y1 = xy[1];
 47 
 48         double x2 = 0, y2 = 0;
 49         xy = processData(point2);
 50         x2 = xy[0];
 51         y2 = xy[1];
 52         if (points.length != 2) {
 53             System.out.print("wrong number of points");
 54             System.exit(0);
 55         }
 56         if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6) {
 57             System.out.print("points coincide");
 58             System.exit(0);
 59         }
 60         if (Math.abs(x1 - x2) < 1e-6) {
 61             System.out.print("Slope does not exist");
 62             System.exit(0);
 63         }
 64 
 65         return (y1 - y2) / (x1 - x2);
 66     }
 67 
 68     /**
 69      * 判断三点是否在一条直线上
 70      */
 71     public static boolean isColinear(String data) {
 72         String[] points = data.split(" ");
 73 
 74         String point3 = points[2];
 75         String point1 = points[0];
 76         String point2 = points[1];
 77         double x1 = 0, y1 = 0;
 78         double[] xy = processData(point1);
 79         x1 = xy[0];
 80         y1 = xy[1];
 81 
 82         double x2 = 0, y2 = 0;
 83         xy = processData(point2);
 84         x2 = xy[0];
 85         y2 = xy[1];
 86 
 87         double x3 = 0, y3 = 0;
 88         xy = processData(point3);
 89         x3 = xy[0];
 90         y3 = xy[1];
 91 
 92         if (points.length != 3) {
 93             System.out.print("wrong number of points");
 94             System.exit(0);
 95         }
 96 
 97         if (Math.abs(x2 - x3) < 1e-6 && Math.abs(y2 - y3) < 1e-6) {
 98             System.out.print("points coincide");
 99             System.exit(0);
100         } else if (Math.abs(x1 - x3) < 1e-6 && Math.abs(y1 - y3) < 1e-6) {
101             System.out.print("points coincide");
102             System.exit(0);
103         } else if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6) {
104             System.out.print("points coincide");
105             System.exit(0);
106         }
107 
108         if (Math.abs(x1 - x2) > 1e-6) {
109             double k = calculateSlope(points[0] + " " + points[1]);
110             double b = y1 - k * x1;
111             return Math.abs(k * x3 + b - y3) < 1e-6;
112         } else {
113             return Math.abs(x1 - x3) < 1e-6;
114         }
115 
116     }
117 
118     /**
119      * 判断是否平行
120      */
121     public static boolean isParallel(String data) {
122         String[] points = data.split(" ");
123         String point1 = points[0], point2 = points[1], point3 = points[2], point4 = points[3];
124 
125         double x1 = 0, y1 = 0;
126         double[] xy = processData(point1);
127         x1 = xy[0];
128         y1 = xy[1];
129 
130         double x2 = 0, y2 = 0;
131         xy = processData(point2);
132         x2 = xy[0];
133         y2 = xy[1];
134 
135         double x3 = 0, y3 = 0;
136         xy = processData(point3);
137         x3 = xy[0];
138         y3 = xy[1];
139 
140         double x4 = 0, y4 = 0;
141         xy = processData(point4);
142         x4 = xy[0];
143         y4 = xy[1];
144         if (points.length != 4) {
145             System.out.print("wrong number of points");
146             System.exit(0);
147         }
148         if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6
149                 || Math.abs(x3 - x4) < 1e-6 && Math.abs(y3 - y4) < 1e-6) {
150             System.out.print("points coincide");
151             System.exit(0);
152         }
153 
154         if (Math.abs(x1 - x2) > 1e-6 && Math.abs(x3 - x4) > 1e-6) {
155             double k1 = calculateSlope(point1 + " " + point2);
156             double k2 = calculateSlope(point3 + " " + point4);
157             return Math.abs(k1 - k2) < 1e-6;
158         } else return Math.abs(x1 - x2) < 1e-6 && Math.abs(x3 - x4) < 1e-6;
159     }
160 
161     /**
162      * 判断交点位置
163      */
164     public static boolean isIntersectWithinSegment(String data) {
165         String[] points = data.split(" ");
166         String point1 = points[0], point2 = points[1], point3 = points[2], point4 = points[3];
167 
168         double x1 = 0, y1 = 0;
169         double[] xy = processData(point1);
170         x1 = xy[0];
171         y1 = xy[1];
172 
173         double x2 = 0, y2 = 0;
174         xy = processData(point2);
175         x2 = xy[0];
176         y2 = xy[1];
177 
178         double x3 = 0, y3 = 0;
179         xy = processData(point3);
180         x3 = xy[0];
181         y3 = xy[1];
182 
183         double x4 = 0, y4 = 0;
184         xy = processData(point4);
185         x4 = xy[0];
186         y4 = xy[1];
187 
188         if (points.length != 4) {
189             System.out.print("wrong number of points");
190             System.exit(0);
191         }
192         if (Math.abs(x1 - x2) < 1e-6 && Math.abs(y1 - y2) < 1e-6
193                 || Math.abs(x3 - x4) < 1e-6 && Math.abs(y3 - y4) < 1e-6) {
194             System.out.print("points coincide");
195             System.exit(0);
196         }
197         if (Math.abs(x1 - x2) < 1e-6 && Math.abs(x3 - x4) < 1e-6) {
198             System.out.print("is parallel lines,have no intersection point");
199             System.exit(0);
200         }
201         if ( Math.abs(x1 - x2) < 1e-6) {
202             double k = calculateSlope(point3 + " " + point4);
203             double b = y4 - k * x4;
204             double y = k * x1 + b;
205             System.out.print(x1 + " " + y + " ");
206             return (y < Math.max(y1, y2) && y > Math.min(y1, y2)) || (x1 < Math.max(x3, x4) && x1 < Math.min(x3, x4));
207         }
208         if ( Math.abs(x3 - x4) < 1e-6) {
209             double k = calculateSlope(point1 + " " + point2);
210             double b = y1 - k * x1;
211             double y = k * x3 + b;
212             System.out.print(x3 + " " + y + " ");
213             return (y < Math.max(y3, y4) && y > Math.min(y3, y4)) || (x3 < Math.max(x1, x2) && x3 > Math.min(x2, x1));
214         }
215         double k1 = calculateSlope(point1 + " " + point2), k2 = calculateSlope(point3 + " " + point4);
216         if ( Math.abs(k1 - k2) < 1e-6) {
217             System.out.print("is parallel lines,have no intersection point");
218             System.exit(0);
219         }
220         double b1 = y1 - k1 * x1;
221         double b2 = y3 - k2 * x3;
222         double x = (-b1 + b2) / (k1 - k2);
223         double y = - (k1 * b2 - k2 * b1) / (k2 - k1);
224         System.out.print(x + " " + y + " ");
225         return (x < Math.max(x1, x2) && x > Math.min(x1, x2)) || (x < Math.max(x3,x4) && x > Math.min(x3, x4));
226     }
227 
228     /**
229      * 计算点到直线的距离
230      */
231     public static double calculateDistance(String data) {
232         String[] points = data.split(" ");
233 
234         String point3 = points[2];
235         String point1 = points[0];
236         String point2 = points[1];
237         double x1 = 0, y1 = 0;
238         double[] xy = processData(point1);
239         x1 = xy[0];
240         y1 = xy[1];
241 
242         double x2 = 0, y2 = 0;
243         xy = processData(point2);
244         x2 = xy[0];
245         y2 = xy[1];
246 
247         double x3 = 0, y3 = 0;
248         xy = processData(point3);
249         x3 = xy[0];
250         y3 = xy[1];
251         if (points.length != 3) {
252             System.out.print("wrong number of points");
253             System.exit(0);
254         }
255         if (Math.abs(x3 - x2) < 1e-6 && Math.abs(y3 - y2) < 1e-6) {
256             System.out.print("points coincide");
257             System.exit(0);
258         }
259 
260         if (Math.abs(x2 - x3) > 1e-6) {
261             double k = calculateSlope(points[1] + " " + points[2]);
262             double b = y1 - k * x1;
263             return Math.abs(k * x1 + b - y1) / Math.sqrt(k * k - 1);
264         } else {
265             return Math.abs(x1 - x2);
266         }
267 
268     }
269 
270     public static void check(String point, int pos) {
271         for (int loop = 0; loop < point.length(); loop++) {
272             if (point.charAt(loop) == '.') {
273                 if (loop == 0 || loop == pos + 1) {
274                     System.out.print("Wrong Format");
275                     System.exit(0);
276                 }
277             }
278             if (point.charAt(loop) == '.') {
279                 if (loop == pos - 1 || loop == point.length() - 1) {
280                     System.out.print("Wrong Format");
281                     System.exit(0);
282                 }
283             }
284         }
285         if (point.charAt(0) == '0' && point.charAt(1) != '.' && point.charAt(1) != ',') {
286             System.out.print("Wrong Format");
287             System.exit(0);
288         } else if (point.length() > pos + 2) {
289             if (point.charAt(pos + 1) == '0' && point.charAt(pos + 2) != '.' && point.charAt(pos + 2) != ',') {
290                 System.out.print("Wrong Format");
291                 System.exit(0);
292             }
293         }
294     }
295 
296     public static double[] processData(String point) {
297         double x = 0, y = 0;
298         int pos = 0;
299         for (int loop = 0; loop < point.length(); loop++) {
300             if (point.charAt(loop) == ',') {
301                 pos = loop;
302             }
303         }
304         check(point, pos);
305         x = Double.parseDouble(point.substring(0, pos));
306         y = Double.parseDouble(point.substring(pos + 1));
307         return new double[]{x, y};
308     }
309 }

分析:为了追求解题速度,没有进行类的设计,使用了函数式编程,代码没有体现OOP的特性。函数可复用性也很差,基本都是硬编码出来的垃圾代码。给后续的迭代造成了很大的麻烦。


第一次迭代

 题目描述:

面向对象程序设计第二单元总结-LMLPHP

类图:同样没有进行类的设计。

源码(源码太长,这里只给出Main方法):

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String line = in.nextLine();
        try {
            int coi = Integer.parseInt(line.substring(0, 1));
            if (coi < 1 || coi > 5) {
                System.out.print("Wrong Format");
                System.exit(0);
            }
            switch (coi) {
                case 1:
                    judgeTriangle(line.substring(2));
                    break;
                case 2:
                    calculateAttribute(line.substring(2));
                    break;
                case 3:
                    judgeAngle(line.substring(2));
                    break;
                case 4:
                    System.out.println("The point is on the edge of the triangle");
                    break;
                case 5:
                    System.out.println("in the triangle");
                    break;
            }
        } catch (Exception e) {
            System.out.print("Wrong Format");
            System.exit(0);
        }
    }
}

分析:由于第一次使用了函数式的编程,没有做类的设计,在时间紧张的情况下我只能对第一次的代码进行更改和扩充。这导致编码过程非常痛苦,每一个函数的内聚性都不高,几乎需要重写每一个函数。没有进行类的设计浪费了我大量的时间。


第二次迭代:

题目描述:

面向对象程序设计第二单元总结-LMLPHP

类图:

面向对象程序设计第二单元总结-LMLPHP

分析:

  设计了点,线和四边形类,对它们进行了封装。设计ParseInput类对输入进行处理,得到整洁的数据,方便之后的运算。在四边形类中,将四个点作为其的私有属性,设置check方法检测自身能否成为四边形,以及判断是否为特殊四边形的方法。在Line类中,将两个Point对象作为其私有属性,设置getSlope方法,与hasSlope方法共同获取斜率。添加isOnline(Point point), isBetween(Point point)和isSameSide(Point point)方法来判断点与直线的关系。isParallel(Line line)方法判断两条直线的关系。 

心得:

  通过两次迭代,我切实体会到了先设计再编码的重要性了。不通过严谨设计写出来的代码,不用谈什么面向对象程序设计原则,也不存在什么可扩展性。一时追求解题速度可能后面要花上几倍,几十倍的时间来重构代码。不如在编写之前就做好设计,也许刚开始进度会比别人慢,但是越迭代到后期,每一次的工作量就会比硬编码少得多。

 


链表练习

  源码:

class LinkedList<E> implements LinearLIstInterface<E> {
    private Node<E> last;
    private Node<E> first;
    private int length;

    public LinkedList() {
        this.length = 0;
        last = new Node<>();
        first = new Node<>();
    }

    @Override
    public boolean isEmpty() {
        return length == 0;
    }

    @Override
    public int size() {
        return length;
    }

    public void addFirst(E o) {
        if(this.isEmpty()) {
            this.first = new Node<>(o);
            this.last = this.first;
        } else {
            Node<E> temp = new Node<>(o);
            temp.setNext(first);
            this.first = temp;
        }
        length++;
    }

    public void addLast(E o) {
        if (this.isEmpty()) {
            addFirst(o);
        } else {
            Node<E> temp = new Node<>(o);
            last.setNext(temp);
            last = temp;
            length++;
        }

    }

    @Override
    public void add(E o) {
        if (this.isEmpty()) {
            addFirst(o);
        } else {
            addLast(o);
        }
    }

    @Override
    public void printList() {
        Node<E> loop = first;
        System.out.print("[ ");
        while (loop != null) {
            System.out.print(loop.getO().toString() + " ");
            loop = loop.getNext();
        }
        System.out.println("]");
    }

    @Override
    public void add(int index, E o) {
        if ( index < 0 || index > length - 1) {
            System.out.println("Wrong Index");
            System.exit(0);
        }
        if (index == 0) {
            addFirst(o);
        } else if (index == length - 1) {
            addLast(o);
        } else {
            int pos = 0;

            Node<E> loop = first;
            while (loop != null) {
                if ( pos + 1 == index) {
                    Node<E> temp = new Node<>(o);
                    temp.setNext(loop.getNext());
                    loop.setNext(temp);
                    break;
                }
                pos++;
                loop = loop.getNext();
            }
        }
        length++;
    }

    @Override
    public void remove(int index) {
        if ( index < 0 || index > length - 1) {
            System.out.println("Wrong Index");
            System.exit(0);
        }
        int pos = 0;
        Node<E> loop = first;
        while (loop != null) {
            if (pos + 1 == index) {
                loop.setNext(loop.getNext().getNext());
                break;
            } else {
                pos++;
            }
            loop = loop.getNext();
        }
        length--;
    }

    @Override
    public E get(int index) {
        if (index < 0 || index > length - 1) {
            System.out.println("Wrong Index");
            System.exit(0);
        }
        int pos = 0;
        for (Node<E> loop = first; loop.getNext() == null; loop = loop.getNext()) {
            if (pos == index) {
                return loop.getO();
            }
            pos++;
        }
        return null;
    }

}


期中考试题目总结

第一题:

题目描述:

面向对象程序设计第二单元总结-LMLPHP

类图:

面向对象程序设计第二单元总结-LMLPHP

分析:由于给出了类图,当时写题得时候非常快,照着类图写就是了,没什么大问题。


第二题

题目描述:

面向对象程序设计第二单元总结-LMLPHP

 类图:

面向对象程序设计第二单元总结-LMLPHP

 分析:这一题的关键就是把Element类抽象出来,再通过子类复写父类方法实现多态。


 第三题:

题目描述:

面向对象程序设计第二单元总结-LMLPHP

源码:

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        double x1;
        double y1;
        double x2;
        double y2;
        String color;
        GeometryObject geometryObject = new GeometryObject();
        int choice = in.nextInt();
        while(choice != 0){
            switch(choice) {
                case 1: x1 = in.nextDouble();
                y1 = in.nextDouble();
                    if (x1 < 0 || x1 > 200 || y1 < 0 || y1 > 200) {
                        System.out.println("Wrong Format");
                        System.exit(0);
                    } else
                        geometryObject.add(new Point(x1, y1));
                //insert Point object into list
                    break;
                case 2:x1 = in.nextDouble();
                    y1 = in.nextDouble();
                    x2 = in.nextDouble();
                    y2 = in.nextDouble();
                    color = in.next();
                    if (x1 < 0 || x1 > 200 || y1 < 0 || y1 > 200 || x2 < 0 || x2 > 200 || y2 < 0 || y2 > 200) {
                        System.out.println("Wrong Format");
                        System.exit(0);
                    } else
                        geometryObject.add(new Line(new Point(x1, y1), new Point(x2, y2), color));//insert Line object into list
                    break;
                case 3:color = in.next();
                geometryObject.add(new Plane(color));//insert Plane object into list
                    break;
                case 4:int index = in.nextInt();
                if (index > geometryObject.getList().size() || index < 1){
                    choice = in.nextInt();
                    continue;
                }
                geometryObject.remove(index - 1);//delete index - 1 object from list
                    break;
            }
            choice = in.nextInt();

        }
        for(Element element:geometryObject.getList()){
            element.display();
        }
    }
}

abstract class Element {
    public abstract void display();
}

class Point extends Element {
    private double x;
    private double y;

    public Point(double x, double y) {
        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;
    }

    @Override
    public void display() {
        System.out.printf("(%.2f,%.2f)%n", x, y);
    }
}

class Line extends Element {
    private Point point1;
    private Point point2;
    private String color;

    public Line(Point point1, Point point2, String color) {
        this.point1 = point1;
        this.point2 = point2;
        this.color = color;
    }

    public Point getPoint1() {
        return point1;
    }

    public void setPoint1(Point point1) {
        this.point1 = point1;
    }

    public Point getPoint2() {
        return point2;
    }

    public void setPoint2(Point point2) {
        this.point2 = point2;
    }

    public double getDistance() {
        return Math.sqrt((getPoint1().getX() - getPoint2().getX()) * (getPoint1().getX() - getPoint2().getX())
                + (getPoint1().getY() - getPoint2().getY()) * (getPoint1().getY() - getPoint2().getY()));
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public void display() {
        System.out.println("The line's color is:" + color);
        System.out.println("The line's begin point's Coordinate is:");
        point1.display();
        System.out.println("The line's end point's Coordinate is:");
        point2.display();
        System.out.printf("The line's length is:%.2f%n", getDistance());
    }
}

class Plane extends Element {
    private String color;

    public Plane(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public void display() {
        System.out.println("The Plane's color is:" + color);
    }
}

class GeometryObject{
    private ArrayList<Element> list = new ArrayList<>();

    public GeometryObject() {
    }

    public GeometryObject(ArrayList<Element> list) {
        this.list = list;
    }

    public ArrayList<Element> getList() {
        return list;
    }

    public void setList(ArrayList<Element> list) {
        this.list = list;
    }

    public void add(Element element){
        list.add(element);
    }

    public void remove(int index){
        list.remove(index);
    }
}

 类图:

面向对象程序设计第二单元总结-LMLPHP

 分析:GeometryObject类中有用到泛型和ArrayList数据类型,在Main方法中使用了foreach循环。


踩坑心得:

  先动笔再动手!先动笔再动手!先动笔再动手!后期改代码真的是折磨,如果前期做好类的设计,只要需求大体不变,迭代起来非常轻松。


总结:

  掌握一些基本的数据结构用法,浅学了一下Java FX,还有几种设计模式,以及lambda表达式和Stream 的简单使用。觉得自己还是需要加强类设计的能力,有时长时间设计不出来类图,非常难受,有时类的设计又太过复杂,很难实现。在设计类和害怕设计的太过复杂之中患得患失。所以有必要加强一下设计能力。

 

05-01 20:02