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.有一些类也可以和其他类一样变成父类的子类,应该尽量减少代码的重复率,提高代码的利用率和可读性。
五、总结
通过几周的学习,我对于类的知识有了更加全面的了解,也更加熟练地掌握了类的各种功能,理解了父类与子类的关系以及如何运用它们更加方便地解决问题,虽然还有一些较难的问题没有完全解决,但是对于基础的知识还是更加明白了。几次作业虽然没有全部满分,但是对于我的学习还是非常有帮助的,提高了我的动手能力,进步了我的专业知识。
浙公网安备 33010602011771号