Java-Day-11(项目零钱通 + 章节练习)
Java-Day-11
项目零钱通
-
功能
- 搭建菜单显示
- 完成零钱明细
- 完成收益入账
- 完成消费功能
- 实现退出完善,进行 y / n 确认
- 判断入账、消费金额的合理性
-
面向过程的代码
package com.hspJava; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; public class SmallChangeSys { public static void main(String[] args){ boolean flag = true; Scanner scanner = new Scanner(System.in); String key = ""; String details = "-------------钱财服务明细-------------"; // 收益 double money = 0; double balance = 0; // 消费 String note = ""; // java.util,Date Date date = null; // 日期格式化 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); do{ System.out.println("========软件钱财服务========"); System.out.println("\t\t\t1 钱财明细"); System.out.println("\t\t\t2 收益入账"); System.out.println("\t\t\t3 消费"); System.out.println("\t\t\t4 退出"); System.out.println("请选择你所要做的操作: 1 ~ 4"); key = scanner.next(); switch (key){ case "1": System.out.println(details); break; case "2": System.out.println("收益入账金额:"); money = scanner.nextDouble(); // 找出不正确金额条件,提示后直接break ——> 一系列判断时,判不正确的更方便些,这样不仅可读性强,后期再添加不正确的情况时也更方便 if (money <= 0){ System.out.println("正确收入金额应大于0"); break; } balance += money; // 获取当前日期 date = new Date(); details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + balance; break; case "3": System.out.println("消费金额:"); money = scanner.nextInt(); if (money <= 0 || money > balance){ System.out.println("消费金额不能为0或者大于余额"); } System.out.println("消费情况:"); note = scanner.next(); balance -= money; date = new Date(); details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + balance; break; case "4": String choice = ""; while(true){ System.out.println("你确定要退出吗? y/n"); choice = scanner.next(); // 一段代码实现一个小功能,这样后期改善、拓展更方便更改,例:除了y、n外再加一个待定... // 尽量不要混合在一起,这样代码耦合性低,提高可读性 if ("y".equals(choice) || "n".equals(choice)){ break; } } if (choice.equals("y")){ flag = false; } // n 就是不退出,就是不做处理 break; default: System.out.println("选择有误,请重新选择"); } }while(flag); } }
-
修改为面向对象 OOP
- SmallChangeSysOOP:完成各个功能
// SmallChangeSysOOP: package com.hspJava.OOP; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; public class SmallChangeSysOOP { boolean flag = true; Scanner scanner = new Scanner(System.in); String key = ""; String details = "-------------钱财服务明细-------------"; // 收益 double money = 0; double balance = 0; // 消费 String note = ""; // java.util,Date Date date = null; // 日期格式化 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); // 被调用的主方法:菜单 public void mainMenu(){ do{ System.out.println("========软件钱财服务OOP========"); System.out.println("\t\t\t1 钱财明细"); System.out.println("\t\t\t2 收益入账"); System.out.println("\t\t\t3 消费"); System.out.println("\t\t\t4 退出"); System.out.println("请选择你所要做的操作: 1 ~ 4"); key = scanner.next(); switch (key){ case "1": this.detail(); break; case "2": this.income(); break; case "3": this.pay(); break; case "4": this.exit(); // n 就是不退出,就是不做处理 break; default: System.out.println("选择有误,请重新选择"); } }while(flag); } // 完成零钱明细 public void detail(){ System.out.println(details); // 此处采用简单的直接拼接的方法放进details里 } // 完成收益入账 public void income(){ System.out.println("收益入账金额:"); money = scanner.nextDouble(); // 找出不正确金额条件,提示后直接break ——> 一系列判断时,判不正确的更方便些,这样不仅可读性强,后期再添加不正确的情况时也更方便 if (money <= 0){ System.out.println("正确收入金额应大于0"); // break; 在面向对象时选择退出方法 return; } balance += money; // 获取当前日期 date = new Date(); details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + balance; } // 消费 public void pay(){ System.out.println("消费金额:"); money = scanner.nextInt(); if (money <= 0 || money > balance){ System.out.println("消费金额不能为0或者大于余额"); return; } System.out.println("消费情况:"); note = scanner.next(); balance -= money; date = new Date(); details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + balance; } // 退出 public void exit(){ String choice = ""; while(true){ System.out.println("你确定要退出吗? y/n"); choice = scanner.next(); // 一段代码实现一个小功能,这样后期改善、拓展更方便更改,例:除了y、n外再加一个待定... // 尽量不要混合在一起,这样代码耦合性低,提高可读性 if ("y".equals(choice) || "n".equals(choice)){ break; } } if (choice.equals("y")){ flag = false; } } }
- SmallChangeSysApp:调用相关方法完成功能
// 在这里直接调用SmallChangeSysOOP对象,显示主菜单即可 public class SmallChangeSysApp { public static void main(String[] args) { new SmallChangeSysOOP().mainMenu(); } }
- 此面向对象的方式,不仅可以供方法给他人使用,在拓展优化功能时可以更方便写入
章节练习
-
Person 数组存三个对象,按对象年龄从大到小冒泡排序
// main Person[] persons = new Person[3]; persons[0] = new Person(...); persons[1] = new Person(...); persons[2] = new Person(...); for(int i = 0; i < persons.length - 1; i++){ // 外部 for(int j = 0; j < person.lenth - 1 - i, j++){ // 内部每次定最后一个 System.out.println(); // 用于交换的临时变量 Person tmp = null; if(persons[i].getAge() < person[i + 1].getAge()){ tmp = person[i]; person[i] = person[i + 1]; person[i + 1] = tmp; } } }
- 若是看名字长度,就persons[i].getName().length
-
编写对象时,若是姓名、固定工资等可以写进构造器中,但若是奖金等可能会变化的值就最好不要写进构造器里,而是用 get、set 方法,于需要时 get 获取,main 里 set 存入
// 若是继承了父类的day属性,在计算工资时就可以在子类中使用get方法 public void printSal(){ System.out.println("管理层" + getname() + "的工资是" + (bonus + getDaySal() * getGrade()) + "。"); } // 若是没有特殊加奖金等要求,就可以直接继承父类方法,无需像上述管理层那样重写 public void printSal(){ super.printSal(); }
-
设计父类——员工类,子类:农民类 ( Peasant ),教师类 ( Teaher ),科学家类 ( Scientist )
- 其中农民只有基本工资
- 教师除了基本工资外,还有课酬 ( 元/天 )
- 科学家除基本工资外还有年终奖
- 编写一个测试类,将各种类型的员工的全年工资打印出来
// 父类——员工类 public class Employee { private String name; private double sal; // 带薪月份:salMonth,这里假设是12个月 private int salMonth = 12; public Employee(String name, double sal) { this.name = name; this.sal = sal; } public void printSal(){ System.out.println(name + "的年工资是:" + (sal * salMonth)); } public double printSaltest(){ return sal * salMonth; } // 此处省略所有私有属性的get、set方法 } // 农民类 public class Peasant extends Employee{ public Peasant(String name, double sal) { super(name, sal); } public void printSal(){ System.out.print("农民"); super.printSal(); } } // 教师类 public class Teacher extends Employee{ private int classDays; // 一天课时 private double classSal; // 课时费 public Teacher(String name, double sal) { super(name, sal); } public void printSal() { System.out.print("老师"); System.out.println(getName() + "的年工资是:" + (getSal() * getSalMonth() + classSal * classDays)); } // 此处省略私有属性的get、set方法 } // 科学家类 public class Scientist extends Employee{ private double bonus; public Scientist(String name, double sal) { super(name, sal); } @Override public void printSal() { System.out.println("科学家"); System.out.println("*****用(getSal() * getSalMonth() + bonus)"); System.out.println(getName() + "的年工资是:" + (getSal() * getSalMonth() + bonus)); System.out.println("*****用(getSal() * getSalMonth() + getBonus())"); System.out.println(getName() + "的年工资是:" + (getSal() * getSalMonth() + getBonus())); System.out.println("*****用(super.printSaltest() + bonus),前提是父类有一个方法printSaltest()是返回double类型的纯工资计算式结果"); System.out.println(getName() + "的年工资是:" + super.printSaltest() + bonus); System.out.println("*****因为前面有字符串,所以上面输出的是字符串拼接后加bonus,所以要像下面括号括起来先"); System.out.println(getName() + "的年工资是:" + (super.printSaltest() + bonus)); } // 私有属性的get、set方法 public double getBonus() { return bonus; } public void setBonus(double bonus) { this.bonus = bonus; } } // main所在 public class SalTest { public static void main(String[] args) { Peasant p1 = new Peasant("小一", 1000); // 可随时更改带薪月份,从而更改了年薪 // p1.setSalMonth(10); p1.printSal(); Teacher t1 = new Teacher("小二", 2000); t1.setClassDays(365); t1.setClassSal(100); t1.printSal(); Scientist s1 = new Scientist("小四", 2000); s1.setBonus(5); s1.printSal(); } } /* 输出为 农民小一的年工资是:12000.0 老师小二的年工资是:60500.0 科学家 *****用(getSal() * getSalMonth() + bonus) 小四的年工资是:24005.0 *****用(getSal() * getSalMonth() + getBonus()) 小四的年工资是:24005.0 *****用(super.printSaltest() + bonus),前提是父类有一个方法printSaltest()是返回double类型的纯工资计算式结果 小四的年工资是:24000.05.0 *****因为前面有字符串,所以上面输出的是字符串拼接后加bonus,所以要像下面括号括起来先 小四的年工资是:24005.0 Process finished with exit code 0 */
-
勿混淆 this、super
-
this:当前对象开始,向上到父类、超类 ...
-
super:子类中访问的父类对象开始,向上访问到超类 ...
-
不管 this 还是 super 都要遵守访问权限、就近原则
class Test{ String name = "ZHANG"; Test(String name){ this.name = name; } } class Demo extends Test{ String name = "ZHU"; Demo(String s){ super(s); } public void test(){ System.out.print(super.name); System.out.print(this.name); } public static void main(String[] args){ new Demo("jojo").test(); // 输出为 jojo ZHU } }
-
-
银行存款取款 — BankAccount,
- BankAccount 基础上扩展,建一个新类 CheckingAccount,每次存、取款都要加一块钱的手续费
- BankAccount 基础上扩展,建一个新类 SavingsAccount,每个月都有利息产生,并且每月三次免手续费的存或取款
// 父类 public class BankAccout { private double balance; public BankAccout(double initiaBalance){ this.balance = initiaBalance; } // 存款 public void deposit(double amount){ balance += amount; } // 取款 public void withdraw(double amount){ balance -= amount; } // set、get 方法 } // 子CheckingAccount public class CheckingAccount extends BankAccout{ public CheckingAccount(double initiaBalance) { super(initiaBalance); } public void deposit(double amount){ // 这样就无需重写,巧用父类 super.deposit(amount - 1); } public void withdraw(double amount){ // 父类减钱减的是amount,所以这里是加1 super.withdraw(amount + 1); } } // 子SavingsAccount public class SavingsAccount extends BankAccout{ private int count = 3; private double rate = 0.1; public SavingsAccount(double initiaBalance) { super(initiaBalance); } @Override public void deposit(double amount) { // 判断是否还可以免手续费 if (count > 0){ super.deposit(amount); } else { super.deposit(amount - 1); } count--; } @Override public void withdraw(double amount) { if (count > 0){ super.withdraw(amount); } else { super.withdraw(amount + 1); } count--; } // 每个月初,统计上个月的利息,同时将count=3 public void earnMonthlyInterest(){ count = 3; super.deposit(getBalance() * rate); } // set、get 方法 } // test测试 public class SalTest { public static void main(String[] args) { CheckingAccount checkingAccount = new CheckingAccount(1000); checkingAccount.deposit(10); System.out.println(checkingAccount.getBalance()); // 1009.0 SavingsAccount savingsAccount = new SavingsAccount(100); savingsAccount.deposit(10); savingsAccount.deposit(10); savingsAccount.deposit(10); System.out.println(savingsAccount.getBalance()); // 130 savingsAccount.deposit(10); System.out.println(savingsAccount.getBalance()); // 130 + 10 - 1 = 139 // 假设月初了 savingsAccount.earnMonthlyInterest(); System.out.println(savingsAccount.getBalance()); // 139 + 139 * 0.1 = 152.9 } }
-
向上转型和向下转型
class Person{ public void sing(){ System.out.println("person sing"); } public void dance(){ System.out.println("person dance"); } } class Student extends Person{ public void sing(){ System.out.println("Student sing"); } public void rap(){ System.out.println("Student rap"); } } // 向下转型:编译类型是p, Person p = new Student(); p.sing(); // 调用就动态绑定机制,运行是从子类开始找实现内容——Student sing p.dance(); // 子类没有再去父类找——person dance // p.rap 用不了,只有编译类型的方法能用 //向下转型:把指向子类对象的父类引用,转成指向子类的子类引用,编译类型变成子类,此时一个指向堆的p一个s Student s = (Student)p; s.sing(); // Student sing s.rap(); // Student rap s.dance(); // person dance
-
定义方法,形参为父类 Person 类型,功能:调用 Student 的 study 方法或者老师 Teacher 的 teach 方法
public void test(Person p) { if(p instanceof Student) { ((Student) p).study(); } else if(p instanceof Teacher) { ((Teacher) p).teach(); } else { System... } }
-
区分 == 与 equals
名称 概念 用于基本数据类型 用于引用类型 == 比较运算符 可以,判断值是否相等 可以,判断是否是同一个对象 equals Object 类的方法,Java 类都可以使用 不可以 可以,默认判断两个对象是否相等,但是子类往往重写为比较对象的属性是否相同 -
多态:方法或对象具有多种状态,是 OOP 的第三大特征,是建立在封装和继承基础之上的
- 体现
- 方法:重载、重写
- 对象:编译类型可以与运行类型不同,编译类型不可改变,但运行类型可以变化,可以用 .getClass() 来查看运行类型
- 向上转型:父 = new 子;超 = new 父 / 子 ;超 = 父 / 子切换
- 向下转型:( 父 = new 子 后 ) 子 = ( 子 ) 父
- 体现
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义