BLOG-2

一、前言

  通过这几周的学习,我们对于“类”有了更深的了解,对它的功能的掌握也更加熟练,pta上的作业题目量不多,除了第二道难度大之外,其余两题都能正确完成。期间我们还进行了期中考试、实验题(农夫过河问题)来巩固我们所学的知识。期中考试三道题与数学点与线问题结合,通过设计类的方法,层层递进,一步步完善功能。农夫过河问题主要考察我们对于父类与子类的理解与运用。


二、设计与分析

1、期中考试

(1)

题目要求:

设计一个类表示平面直角坐标系上的点Point,私有属性分别为横坐标x与纵坐标y,数据类型均为实型数,除构造方法以及属性的getter与setter方法外,定义一个用于显示信息的方法display(),用来输出该坐标点的坐标信息,格式如下:(x,y),数值保留两位小数。为简化题目,其中,坐标点的取值范围设定为(0,200]。若输入有误,系统则直接输出Wrong Format。

设计一个类表示平面直角坐标系上的线Line,私有属性除了标识线段两端的点point1、point2外,还有一个字符串类型的color,用于表示该线段的颜色,同样,除构造方法以及属性的getter与setter方法外,定义一个用于计算该线段长度的方法getDistance(),还有一个用于显示信息的方法display(),用来输出线段的相关信息。

 

该题的类图如下:

 

 

 SourceMonitor报表:

部分代码:

点类:

class Point {
    private double x;
    private double y;
    public double getX(){
        return x;
    }
    public double getY(){
        return y;
    }
    public void setX(double x){
        this.x = x;
    }
    public void setY(double y){
        this.y = y;
    }
    public Point(double x,double y) {
        this.x = x;
        this.y = y;
        
    }
    public void display() {
        System.out.println("("+String.format("%.2f",x)+","+String.format("%.2f",y)+")");
    }
}

线类:

class Line{
    private Point point1;
    private Point point2;
    private String color;
    public Point getpoint1(){
        return point1;
    }
    public Point getpoint2(){
        return point2;
    }
    public void setPoint1(Point point1){
        this.point1 = point1;
    }
    public void setPoint2(Point point2){
        this.point2 = point2;
    }
    public String getColor(){
        return color;
    }
    public void setColor(String color){
        this.color = color;
    }
    public Line(Point p1,Point p2,String c){
        point1 = p1;
        point2 = p2;
        color = c;
    }
    public double getDistance() {
        double distance;
        distance = Math.sqrt((point1.getX()-point2.getX())*(point1.getX()-point2.getX())+(point1.getY()-point2.getY())*(point1.getY()-point2.getY()));
        return distance;
    }
    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.println("The line's length is:"+String.format("%.2f",getDistance()));
    }
}

主类:

public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        double x1,y1,x2,y2;
        String color;
        x1 = in.nextDouble();
        y1 = in.nextDouble();
        x2 = in.nextDouble();
        y2 = in.nextDouble();
        if(x1<=0||x1>200||y1<=0||y1>200||x2<=0||x2>200||y2<=0||y2>200) {
            System.out.println("Wrong Format");
            return;
        }
        else {
            color = in.next();
            Point point1 = new Point(x1,y1);
            Point point2 = new Point(x2,y2);
            Line line = new Line(point1, point2, color);
            line.display();
        }
    }
}

本题一开始就将类图告诉了我们,只需要根据类图提示一步步完善设计即可,点类的作用是创建点的对象,其中的私有属性分别是点的横纵坐标,使用get()、set()方法处理x,y,display方法用来输出输入点的坐标,完成点类是完成这个题目的基础。线类与点类相似,只不过属性变成了点类中创建的点对象,还多加了一个代表颜色的color属性,getDistance方法用来得到两点间的距离,display方法用于输出所有需要的信息。主类中首先对输入的点进行合法性判断,之后再解决问题。需要注意的是,其中数据的输出要求保留两位小数,这里我是使用了题目建议的String.format("%.2f", data)方法进行两位小数的保留。

运行结果:

 

(2)

题目要求:

在“点与线(类设计)”题目基础上,对题目的类设计进行重构,以实现继承与多态的技术性需求。

对题目中的点Point类和线Line类进行进一步抽象,定义一个两个类的共同父类Element(抽象类),将display()方法在该方法中进行声明(抽象方法),将Point类和Line类作为该类的子类。

再定义一个Element类的子类面Plane,该类只有一个私有属性颜色color,除了构造方法和属性的getter、setter方法外,display()方法用于输出面的颜色,输出格式如下:The Plane's color is:颜色

在主方法内,定义两个Point(线段的起点和终点)对象、一个Line对象和一个Plane对象,依次从键盘输入两个Point对象的起点、终点坐标和颜色值(Line对象和Plane对象颜色相同),然后定义一个Element类的引用,分别使用该引用调用以上四个对象的display()方法,从而实现多态特性。

类图:

 

 

  SourceMonitor报表:

父类:

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

子类:

class Point extends Element{
    private double x;
    private double y;
    public double getX(){
        return x;
    }
    public double getY(){
        return y;
    }
    public void setX(double x){
        this.x = x;
    }
    public void setY(double y){
        this.y = y;
    }
    public Point(double x,double y) {
        this.x = x;
        this.y = y;
        
    }
    public void display() {
        System.out.println("("+String.format("%.2f",x)+","+String.format("%.2f",y)+")");
    }
}
class Line extends Element{
    private Point point1;
    private Point point2;
    private String color;
    public Point getpoint1(){
        return point1;
    }
    public Point getpoint2(){
        return point2;
    }
    public void setPoint1(Point point1){
        this.point1 = point1;
    }
    public void setPoint2(Point point2){
        this.point2 = point2;
    }
    public String getColor(){
        return color;
    }
    public void setColor(String color){
        this.color = color;
    }
    public Line(Point p1,Point p2,String color){
        point1 = p1;
        point2 = p2;
        this.color = color;
    }
    public double getDistance() {
        double distance;
        distance = Math.sqrt((point1.getX()-point2.getX())*(point1.getX()-point2.getX())+(point1.getY()-point2.getY())*(point1.getY()-point2.getY()));
        return distance;
    }
    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.println("The line's length is:"+String.format("%.2f",getDistance()));
    }
}
class Plane extends Element{
    private String color;
    public String getColor(){
        return color;
    }
    public void setColor(String color){
        this.color = color;
    }
    public Plane(String color){
        this.color = color;
    }
    public void display() {
        System.out.println("The Plane's color is:"+color);
    }
}

这道题是第一题的升级版,通过父类和子类的继承关系对代码进行进一步完善与简化,子类中的大部分内容与前一道题相同,父类中只有一个抽象的display方法,每个子类中也有对display方法的重写,另外还添加了一个面(Plane)的子类用来输出颜色。需要注意的是输出格式是有一定顺序的,应该在不同的类中正确调用display方法以输出答案。

运行结果:

 

 

2.实验题

农夫过河问题

题目要求:

  一个农夫带着一匹狼、一只羊、一颗白菜要过河,河上只有一条船能够渡河,而且农夫每次最多只能带一个动物或物品过河。当农夫不在的时候狼会吃羊,羊会吃白菜。

请以代码为基础,将程序代码补充完整,实现农夫过河游戏功能:由用户选择角色过河,系统自动判断游戏的胜负:当出现有生物被吃掉的时候,游戏失败,所有角色都到了河的另一边,游戏成功。

(1)为之前的类添加合适的父类。

(2)为父类添加适合的属性和方法。并以此为基础修改原有的类,使之与添加的类构成继承关系。

(3)使用多态改进整个代码,提高代码的复用性。

类图:

 

SourceMonitor报表:

父类:

 

abstract class  Object {
    private boolean crossRiver = true;
    private boolean hasCross = false;
    private boolean isAlive = true;
    abstract void showStatus();
    public void change() {
        crossRiver=!(crossRiver);
        hasCross=!(hasCross);
    }
    public boolean getcrossriver() {
        return crossRiver;
    }
    public boolean gethascross() {
        return hasCross;
    }
    public boolean getisalive() {
        return isAlive;
    }
    public void setisalive() {
        isAlive = !isAlive;
    }
    
}

 

狼类:

class Wolf extends Object{
    public void eatSheep(Sheep sheep,Farmer farmer)
    {
        if((super.gethascross()&&sheep.gethascross()&&!farmer.gethascross())||(super.getcrossriver()&&sheep.getcrossriver()&&!farmer.getcrossriver())) {
            sheep.setisalive();
        }
    }
    public void showStatus() {
        System.out.println("Wolf is alive:"+super.getisalive() +"\t"+ "Wolf has Cross:"+super.gethascross());
    }
}

船类:

class Boat{
    public static void cross(Farmer a) {
        a.change();
    }
    public static void cross(Wolf a) {
        a.change();
    }
    public static void cross(Sheep a) {
        a.change();
    }
    public static void cross(Cabbage a) {
        a.change();
    }
}

其余的羊类、菜类、农夫类与狼类大致相同,都是Object的子类,重写了showStatus()方法,船类中的cross()方法是将物品的方位翻转,本题中通过crossRiver代表没过河,hasCross代表已经过河,通过true和false来判断过没过河,isAlive代表是否存活,showStatus()方法用来输出各个对象的状态。使用了super关键字来判断过河和存活问题。本题需要注意的是父类与子类之间的继承关系,以及abstruct抽象类、super关键字、属性封装的知识运用。

继承:

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

抽象类:

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。

父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。

在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

super关键字:

功能:在子类的构造方法中显式的调用父类构造方法。

访问父类的成员方法和变量。

运行结果:

3.pta

(1)

题目要求:

请编写程序,实现如下功能:读入关于蛟龙号载人潜水器探测数据的多行字符串,从给定的信息找出数字字符,输出每行的数字之和。

Scanner in=new Scanner(System.in);
        while(true){
            String s=in.nextLine();
            if(s.equals("end")){
                break;
            }
            String[] a=s.split("\\D+");
            int sum=0;
            for(int i=0 ; i<a.length; i++){
                if(!a[i].equals(""))
                {
                    int number = Integer.parseInt(a[i]);
                    sum+=number;
                }
            }
            System.out.println(sum);
        }

利用正则表达式实现对字符串的处理,\\D+ 表示多个数字,形如 12、44、6763……

(2)设计一个银行业务类

题目要求:编写一个银行业务类BankBusiness,具有以下属性和方法:
(1)公有、静态的属性:银行名称bankName,初始值为“中国银行”。
(2)私有属性:账户名name、密码password、账户余额balance。
(3)银行对用户到来的欢迎(welcome)动作(静态、公有方法),显示“中国银行欢迎您的到来!”,其中“中国银行”自动使用bankName的值。
(4)银行对用户离开的提醒(welcomeNext)动作(静态、公有方法),显示“请收好您的证件和物品,欢迎您下次光临!”
(5)带参数的构造方法,完成开户操作。需要账户名name、密码password信息,同时让账户余额为0。
(6)用户的存款(deposit)操作(公有方法,需要密码和交易额信息),密码不对时无法存款且提示“您的密码错误!”;密码正确、完成用户存款操作后,要提示用户的账户余额,例如“您的余额有1000.0元。”。
(7)用户的取款(withdraw)操作(公有方法,需要密码和交易额信息)。密码不对时无法取款且提示“您的密码错误!”;密码正确但余额不足时提示“您的余额不足!”;密码正确且余额充足时扣除交易额并提示用户的账户余额,例如“请取走钞票,您的余额还有500.0元。”。

 

public class Main{
        public static void main(String[] args){
            Scanner in = new Scanner(System.in);
            BankBusiness account;
            account = new BankBusiness("中国银行");
            account.welcome();
           
            String name;
            int password;
            double balance=0.0;
            name = in.next();
            password = in.nextInt();
            account.kaihu(name,password,balance,in);
            account.deposit(password,balance,in);
            account.withdraw(password,balance,in);
            account.withdraw(password,balance,in);
            account.withdraw(password,balance,in);
            account.welcomeNext();
        }
    }
    class BankBusiness{
        String bankName;
        private String name;
        private int password;
        private double balance;
        public BankBusiness(String n) {
            bankName = n;
        }
        public void welcome() {
            System.out.println(bankName+"欢迎您的到来!");
        }
        public void welcomeNext() {
            System.out.println("请收好您的证件和物品,欢迎您下次光临!");
        }
        public void kaihu(String name,int password,Double balance,Scanner in) {
            this.name = name;
            this.password = password;
            this.balance = balance;
        }
        public void deposit(int password,Double balance,Scanner in) {
            int mima;
            double money;
            mima = in.nextInt();
            money = in.nextDouble();
           
            if(mima==password) {
                this.balance = money;
                System.out.println("您的余额有"+this.balance+"元。");
            }
            else {
                System.out.println("您的密码错误!");
            }
            
        }
        public void withdraw(int password,Double balance,Scanner in) {
            int mima;
            double jiaoyi;
            mima = in.nextInt();
            jiaoyi = in.nextDouble();
            if(mima==password) {
                if(this.balance>jiaoyi) {
                    this.balance = this.balance-jiaoyi;
                    System.out.println("请取走钞票,您的余额还有"+this.balance+"元。");
                }
                else {
                    System.out.println("您的余额不足!");
                }
            }
            else {
                System.out.println("您的密码错误!");
            }
        }
    }

 

本题中两个操作(存款,取款)分别对应两个方法(deposit,withdraw),这里需要注意的是Scanner in = new Scanner(System.in)只定义了一个in对象,在其他类中使用in时,需要将in传入类中,否则会导致错误。

三、踩坑心得

1.在对字符串进行处理时,最好先遍历一遍整个字符串,当不符合格式或输入错误时直接提示用户错误,否则可能导致结果出错。

2.对于全局变量和局部变量需要格外注意,不然容易导致结果出错。全局变量就是从定义的位置起,作用域覆盖整个程序范围的变量。而只在特定的过程或函数中可以访问的变量,被称为局部变量。

3.处理父类和子类关系时,要了解继承的关系和逻辑,不然得出的答案可能会出错。

四、改进建议

1.在代码中多标明注释,以便理解和下次修改。

2.有些代码中有一部分功能相同,可以改成方法,使代码更加简洁,也便于下次对代码进行修改。

3.有一些类也可以和其他类一样变成父类的子类,应该尽量减少代码的重复率,提高代码的利用率和可读性。

五、总结

通过几周的学习,我对于类的知识有了更加全面的了解,也更加熟练地掌握了类的各种功能,理解了父类与子类的关系以及如何运用它们更加方便地解决问题,虽然还有一些较难的问题没有完全解决,但是对于基础的知识还是更加明白了。几次作业虽然没有全部满分,但是对于我的学习还是非常有帮助的,提高了我的动手能力,进步了我的专业知识。

 

posted on 2022-05-09 21:36  xrhmxyrs  阅读(127)  评论(0)    收藏  举报