在完成三次题目集后,我觉得有必要对着次的练习进行一次总结。这次的练习的主要围绕类的继承、多态的使用方法以及接口的应用。java的学习主要需要相关题目的大量练习,如接下来所要提到到的四个比较典型的题目。
在题目集07的7-1题中,题目要求对图形卡片进行排序的小游戏。大致了解一下该题的主要内容:考虑一款适合于小学生的卡片(Card)排序游戏,其规则为随机发放一些卡片给学生,卡片分为 四种形状:圆形(Circle)、矩形(Rectangle)、三角形(Triangle)及梯形(Trapezoid),并给出各种卡片的相应参数,要求学生能够迅速求出各卡片的面积大小然后将卡片按照其面积值从大到小进行排 序同时求出所有卡片的面积之和。图形类层次结构,本次作业要求对卡片排序时使用 Comparable 接口, 即 Card 类需要实现 Comparable 接口中的 CompareTo()方法。在了解了题目的大致要求后,可以得到相关类图,本程序仅用于为学生所玩的游戏提供正确答案的功能,即根据学生得到的卡片种类与数量,给出 排序前和排序后的卡片顺序,同时给出所有卡片的面积之和。在写该代码时,可以参考类图的思路得到代码:
代码输入输出规则 ①输入规则 首先,在一行上输入一串数字(1~4,整数),其中,1 代表圆形卡片,2 代表矩形卡片,3 代表 三角形卡片,4 代表梯形卡片。各数字之间以一个或多个空格分隔,以“0”结束。例如: 1 3 4 2 1 3 4 2 1 3 0 ,然后根据第一行数字所代表的卡片图形类型,依次输入各图形的相关参数,例如:圆形卡片需要 输入圆的半径,矩形卡片需要输入矩形的宽和长,三角形卡片需要输入三角形的三条边长,梯形需要 输入梯形的上底、下底以及高。各数据之间用一个或多个空格分隔。 ②输出规则 : 如果图形数量非法(小于 0)或图形属性值非法(数值小于 0 以及三角形三边不能组成三 角形),则输出“Wrong Format”。如果输入合法,则正常输出,所有数值计算后均保留小数点后两位即可。输出内容如下: 排序前的各图形类型及面积,格式为“图形名称 1:面积值 1 图形名称 2:面积值 2 …图形名称 n:面积值 n ”,注意,各图形输出之间用空格分开,且输出最后存在一个用于分隔的空格;排序后的各图形类型及面积,格式同排序前的输: 所有图形的面积总和,格式为“Sum of area:总面积值。
输入示例 1: 1 5 3 2 0 输出示例 1: Wrong Format 输入示例 2: 4 2 1 3 0 3.2 2.5 0.4 2.3 1.4 5.6 2.3 4.2 3.5 输出示例 2: The original list: Trapezoid:1.14 Rectangle:3.22 Circle:98.52 Triangle:4.02 The sorted list: Circle:98.52 Triangle:4.02 Rectangle:3.22 Trapezoid:1.14 Sum of area:106.91 输入示例 3: 4 2 1 3 0 3.2 2.5 0.4 2.3 1.4 5.6 2.3 4.2 8.4 输出示例 3: Wrong Format。
了解了题目的要求和所需要的的功能后,接下来就是对代码的分析。该题的难度适中,在学习了继承的基础下就可以把正确的代码写出来。该题可以创建七个类,卡片类:Triangle、Circle、Traperoid、Rectangle刚好对应三种卡片。再写一个它们的父类Shape类。我认为写该题的出入口在于知道运用继承以及创建ArrayList类:ArrayList<Integer> list = new ArrayList<Integer>(),这样可以将输入的整形数字放入list中:list.add(num)。再将Shape类放入Card类中,这样的话可以再创建一个ArrayLiat类:ArrayList < Card > cardList=new ArrayList<Card>();将Card类放入ArrayList中,这样的话在list的各个元素中,若输入的数字是1,则
for(int i=0;i<list.size();i++) { if(list.get(i)==1) { double radius=Main.input.nextDouble(); Circle circle=new Circle(radius); Card card=new Card(circle); card.getShape().setName("Circle"); cardList.add(card); }
若list中的元素是2、3、4代码与上类似。在这段代码中规定了图形的基本数据,再将这个新创建的卡放片对象放入Card card=new Card(circle)。card.getShape().setName("Rectangle");这段代码中充分体现了继承的优点:子类可以调用父类中的某些方法。在这题中我还学会了如何简便的对它们的面积大小进行排序:这需要在代码的开头进行声明:import java.util.Collections。
public void toSort() { for(int m=0;m<cardList.size();m++) for(int j=m+1;j<cardList.size();j++) { if(cardList.get(m).getShape().getArea()<cardList.get(j).getShape().getArea()) Collections.swap(cardList, m, j); } }
后面的代码内容主要是写各个类:shape类、Rectangle 类等
class Rectangle extends Shape{ private double length; private double width; Rectangle (double length ,double width){ this.width=width; this.length=length; } public double getArea() { return width*length; } public boolean vaildate() { if(width>0&&length>0) return true; else return false; } }
在写继承时,最看重的是代码的封装性。例如:在主函数中 if(!dealCardList.validate()) 中的validate方法 在dealCardList中
public boolean validate() { for(int i=0;i<cardList.size();i++) { if(!cardList.get(i).getShape().vaildate()) return false; } return true; }
该方法中的validate中包含了各个形状的类中的判断类,这充分体现了代码的封装性和完整性。该代码的总的复杂度为6,复杂度较低。如下图所示:
该题与上一题的结构差不多,但题目要求的输出不一样,所以该题的难度比上一题更难一点,但写的内容大部分还是相同的。
public double caulateAllArea() { double[] sum = new double[4]; for(int j=0;j<cardList.size();j++) { if(cardList.get(j).getShape() instanceof Circle) sum[0] += cardList.get(j).getShape().getArea(); if(cardList.get(j).getShape() instanceof Traperoid) sum[1] += cardList.get(j).getShape().getArea(); if(cardList.get(j).getShape() instanceof Triangle) sum[2] += cardList.get(j).getShape().getArea(); if(cardList.get(j).getShape() instanceof Rectangle) sum[3] += cardList.get(j).getShape().getArea(); } int max = 0; for(int i = 0; i < 4; i ++) if(sum[max] < sum[i]) max = i; return sum[max]; }
得到以上类图:
由代码可的该代码的复杂度:
故该代码的复杂度为9,没有超过11,写的还算简单。这里面还用到了对象转换和instanceof操作符,总是可以将一个子类的实例转换为一个父类的变量,称为向上转换,因为子类的实例总是他父类的实例。当把一个父类的实例转换为它的子类变量时,必须使用转换标记进行显式转换。如果父类对象不是子类的一个实例,就会出现一个运行时异常。
题目集8的atm机类改造设计,就是编写一个银行 ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能。该题比较有难度,但还是有比较清晰的思路。在该题中我学会了如何使用ArrayList类,一级一级的将类放入。先是写银联,如何银联里包含了银行,银行里又有账户和atm,账户里有银行卡,此外还有用户,这样根据它们之间的关系一层层写下去。
class UnionPay { private ArrayList<Bank> bankList = new ArrayList<Bank>(); public UnionPay() { super(); // TODO Auto-generated constructor stub } public UnionPay(ArrayList<Bank> bankList) { super(); this.bankList = bankList; } public ArrayList<Bank> getBankList() { return bankList; } public void setBankList(ArrayList<Bank> bankList) { this.bankList = bankList; } public void addBank(Bank bank) { this.bankList.add(bank); } public void removeBank(Bank bank) { this.bankList.remove(bank); } }
复杂度为8,说明写的代码不会太复杂。其部分代码如下所示:
public class Bank { private String name; private ArrayList<Atm> listAtm = new ArrayList<Atm>(); private ArrayList<User> listUser = new ArrayList<User>(); public Bank() { super(); // TODO Auto-generated constructor stub } public Bank(String name, ArrayList<Atm> listAtm, ArrayList<User> listUser) { super(); this.name = name; this.listAtm = listAtm; this.listUser = listUser; } public String getName() { return name; } public void setName(String name) { this.name = name; } public ArrayList<Atm> getListAtm() { return listAtm; } public void setListAtm(ArrayList<Atm> listAtm) { this.listAtm = listAtm; } public ArrayList<User> getListUser() { return listUser; } public void setListUser(ArrayList<User> listUser) { this.listUser = listUser; } public void listAtmAdd(Atm atm) { listAtm.add(atm); } public void listUserAdd(User user) { listUser.add(user); } }
该题充分利用了ArrayList的优点,ArrayList的大小是灵活的,所以无需提前给定它的大小。当创建一个数组时,它的大小必须给定。
mport java.util.ArrayList; class Unionpay { private ArrayList<Bank> listBank = new ArrayList<Bank>(); public Unionpay() { super(); // TODO Auto-generated constructor stub } public Unionpay(ArrayList<Bank> listBank) { super(); this.listBank = listBank; } public ArrayList<Bank> getListBank() { return listBank; } public void setListBank(ArrayList<Bank> listBank) { this.listBank = listBank; } public void listBankAdd(Bank bank) { listBank.add(bank); } }
题目集9的atm的代码大部分的思路与上一题差不多,但它增加了一些要求,比如说银行账户分为借记账户和贷记账户两种,其中,借记账户不能够透支 取款,而贷记账户可以透支取款(可能需要支付手续费),此外。根据账户 的不同,银行卡一般分为借记卡(针对借记账户)和信用卡(针对贷记账户) 两类。且允许跨行办理相关业 务(例如在中国建设银行的 ATM 机上使用中国工商银行的银行卡进行业务操作),故又需要在原来代码的基础上添加一些新的功能。
代码写的比较长,但总的复杂度就5。相关代码内容如下:
public class CreditAccount extends Account{ private double facility = 0; public CreditAccount() { super(); // TODO Auto-generated constructor stub } public CreditAccount(String accountNO, double balance, User user, Bank bank, double facility) { super(accountNO, balance, user, bank); // TODO Auto-generated constructor stub this.facility = facility; } public double getFacility() { return facility; } public void setFacility(double facility) { this.facility = facility; } }
public class CreditWithdraw extends Withdraw { public CreditWithdraw() { super(); // TODO Auto-generated constructor stub } public CreditWithdraw(ATM atm, Account account, double b1, double b2) { super(atm, account, b1, b2); // TODO Auto-generated constructor stub } @Override public void withdraw() { // TODO Auto-generated method stub double balance = getAccount().getBalance(); if(balance > 0 && balance < getB1()) { setB2(getB2() + (getB1() - balance) * 0.05); } else if(balance < 0) { setB2(getB2() + getB1() * 0.05); } balance = balance - getB1() - getB2(); getAccount().setBalance(balance); } }
系统的测试用例均采用题目中的数据,且所有卡号密码默认为“88888888”, 初始余额均为 10000 元,手续费默认均从银行卡所对应的账户中自动扣除。跨行业务手续费收取比例由 ATM 机隶属银行决定,例如,用户手持中国 工商银行的银行卡在中国建设银行的 ATM 上进行取款操作,则手续费收取比例为 中国建设银行的相应比例,按初始化数据中的规定为取款金额的 2%。跨行查询余额不收取手续费,透支取款手续费由中国银联统一规定为 5%,最大透支金额均为 50000 元。
例如如下代码:
public class DebitWithdraw extends Withdraw { public DebitWithdraw() { super(); // TODO Auto-generated constructor stub } public DebitWithdraw(ATM atm, Account account, double b1, double b2) { super(atm, account, b1, b2); // TODO Auto-generated constructor stub } @Override public void withdraw() { double balance = getAccount().getBalance(); balance = balance - this.getB1() - this.getB2(); getAccount().setBalance(balance); } }
public class CreditWithdraw extends Withdraw { public CreditWithdraw() { super(); // TODO Auto-generated constructor stub } public CreditWithdraw(ATM atm, Account account, double b1, double b2) { super(atm, account, b1, b2); // TODO Auto-generated constructor stub } @Override public void withdraw() { // TODO Auto-generated method stub double balance = getAccount().getBalance(); if(balance > 0 && balance < getB1()) { setB2(getB2() + (getB1() - balance) * 0.05); } else if(balance < 0) { setB2(getB2() + getB1() * 0.05); } balance = balance - getB1() - getB2(); getAccount().setBalance(balance); } }
AraaayList类是一个泛型类,在写该题代码时,arraylist类发挥了重要作用。