前情回顾:https://www.cnblogs.com/DAYceng/category/2227185.html

Object类

equals方法

"=="与equals的区别

"=="是一个比较运算符

  • 双等号既可以判断基本类型,又可以判断引用类型
  • 判断基本类型时是判断值是否相等(如int i= 10)
  • 判断引用类型时是判断地址是否相等,即判定是否为同一个对象

练习题

1.记账软件

面向过程版
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner; public class SmallChangeSys {
//化繁为简
//1、先完成显示菜单,并可以选择菜单给出对应提示
//2、完成资金明细
//3、完成收益入账
//4、消费
//5、退出
//6、用户退出时给提示是否要真的退出
//7、金额校验
public static void main(String[] args) {
//定义相关变量
boolean loop = true;
Scanner scanner = new Scanner(System.in);
String key = "";
//资金明细
//可以用数组存;可以使用对象;可以直接用字符串拼接;
String detail = "----------------明细----------------";
//入账
//需要新的变量
double money = 0;
double balance = 0;
Date date = null;
//用于日期格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
//消费
String note = "";
do{
System.out.println("\n================记账菜单================");
System.out.println("\t\t\t\t1 明细");
System.out.println("\t\t\t\t2 入账");
System.out.println("\t\t\t\t3 消费");
System.out.println("\t\t\t\t4 退出"); System.out.print("输入选项1~4: ");
key = scanner.next();
//switch判断
switch (key){
case "1":
System.out.println(detail);
break;
case "2":
System.out.println("收益入账金额:");//输入值校验
money = scanner.nextDouble();
//找不正确的条件,给出提示,直接 break
if(money <= 0){
System.out.println("收益金额需要大于0");
break;
}
balance += money;
//获取当前日期
date = new Date();
detail += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + + balance;
break;
case "3":
System.out.println("消费金额:");
money = scanner.nextDouble();
//找不正确的条件,给出提示,直接 break
if(money <= 0){
System.out.println("消费金额需要大于0");
break;
}
System.out.println("消费说明:");
note = scanner.next();
balance -= money;
//获取当前日期
date = new Date();
detail += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + + balance;
break;
case "4":
//定义一个变量choice,接受输入
//使用while-break,处理接受到的输入是y or n
//退出while循环后再判断输入的是什么
String choice = "";
while (true){
System.out.println("你确定要退出?y/n");
choice = scanner.next();
if("y".equals(choice)||"n".equals(choice)){
break;
}
}
if (choice.equals("y")){
loop = false;
}else {
loop = true;
}
break;
default:
System.out.println("选择有误请重试");
}
}while (loop);
System.out.println("----------------退出软件----------------");
}
}
OOP版

SmallChangeSysOOP,功能类。

实际上就是将之前的各个部分的功能代码封装到类方法中,这样mainMenu()主菜单类只需要去调用本类的方法即可实现所有功能

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
/*
* 完成记账软件的各个功能
* 将各个功能对应一个方法
* */
public class SmallChangeSysOOP {
//属性
boolean loop = true;
Scanner scanner = new Scanner(System.in);
String key = ""; //资金明细
//可以用数组存;可以使用对象;可以直接用字符串拼接;
String detail = "----------------明细----------------"; //入账
//需要新的变量
double money = 0;
double balance = 0;
Date date = null;
//用于日期格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //消费
String note = ""; //先完成显示菜单
public void mainMenu(){
do{
System.out.println("\n================记账菜单OOP================");
System.out.println("\t\t\t\t1 明细");
System.out.println("\t\t\t\t2 入账");
System.out.println("\t\t\t\t3 消费");
System.out.println("\t\t\t\t4 退出"); System.out.print("输入选项1~4: ");
key = scanner.next();
//switch判断
switch (key){
case "1":
this.detail();
break;
case "2":
this.income();
break;
case "3":
this.pay();
break;
case "4":
this.exit();
break;
default:
System.out.println("选择有误请重试");
}
}while (loop);
}
//明细
public void detail(){
System.out.println(detail);
}
//入账
public void income(){
System.out.println("收益入账金额:");//输入值校验
money = scanner.nextDouble();
//找不正确的条件,给出提示,直接 return
if(money <= 0){
System.out.println("收益金额需要大于0");
return;
}
balance += money;
//获取当前日期
date = new Date();
detail += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + + balance;
}
//消费
public void pay(){
System.out.println("消费金额:");
money = scanner.nextDouble();
//找不正确的条件,给出提示,直接 break
if(money <= 0){
System.out.println("消费金额需要大于0");
return;
} System.out.println("消费说明:");
note = scanner.next();
balance -= money;
//获取当前日期
date = new Date();
detail += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + + balance;
}
//退出
public void exit(){
//定义一个变量choice,接受输入
//使用while-break,处理接受到的输入是y or n
//退出while循环后再判断输入的是什么
String choice = "";
while (true){
System.out.println("你确定要退出?y/n");
choice = scanner.next();
if("y".equals(choice)||"n".equals(choice)){
break;
}
}
if (choice.equals("y")){
loop = false;
}else {
loop = true;
}
}
}

SmallChangeSysApp,调用功能类实现软件功能

/*
* 调用SmallChangeSysOOP对象,显示主菜单即可*/
public class SmallChangeSysApp {
public static void main(String[] args) {
new SmallChangeSysOOP().mainMenu();
}
}

2.类方法复用(扩展银行类的练习)

扩展如下的BankAccount类

class BankAccount{
private double balance ;
public BankAccount(double initialBalance){
this.balance = initialBalance;
}
public void deposit(double amount){
balance += amount;
}
public void withdraw(double amount){
balance -= amount;
}
}
  • 要求:

    (1)在上面类的基础上扩展新类CheckingAccount对每次存款和取款都收取1美元的手续费

    (2)扩展前一个练习的BankAccount类,新类SavingsAccount每个月都有利息产生

    (earnMonthlylnterest方法被调用),并且有每月三次免手续费的存款或取款。在earnMonthlylnterest方法中重置交易计数

需求一

扩展后的新类CheckingAccount,只需充分利用父类方法即可

//在上面类的基础上扩展新类CheckingAccount对每次存款和取款都收取1美元的手续费
public class CheckingAccount extends BankAccount{
//属性
public CheckingAccount(double initialBalance) {
super(initialBalance);
} @Override
public void deposit(double amount) {//存款
super.deposit(amount - 1);//利用父类的deposit
//继承父类的存款方法deposit,但是每次存款都少记账1¥,相当于扣除手续费
} @Override
public void withdraw(double amount) {
super.withdraw(amount + 1);//同理,每次取款多扣1¥
}
}

需求二

扩展后的新类SavingsAccount

/*
* 新类SavingsAccount每个月都有利息产生(earnNonthlyInterest方法被调用),
* 并且有每月三次免手续费的存款或取款。
* 在earnMonthlyInterest方法中重置交易计数
*/
public class SavingsAccount extends BankAccount{
private int count = 3;
private double rate = 0.01;//利率 //正经写项目时,新增方法写在最后
public void earnMonthlylnterest(){//每个月初统计上个月的利息,同时将count重置
count = 3;
super.deposit(getBalance() * rate);//复用父类方法
} @Override
public void deposit(double amount) {
//判断是否还可以免手续费
if(count > 0){
super.deposit(amount);
}else {
super.deposit(amount - 1);//扣手续费
}
count--;//减去一次机会
} public SavingsAccount(double initialBalance) {
super(initialBalance); } public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public double getRate() {
return rate;
} public void setRate(double rate) {
this.rate = rate;
}
}

测试类

待拓展的BankAccount类我写在了测试类中,当做父类方法供拓展的子类继承

public class Homework08 {
public static void main(String[] args) {
//// CheckingAccount checkingAccount = new CheckingAccount(1000);
//// System.out.println(checkingAccount.Accountinfo());
//// System.out.println(checkingAccount.deposit(500));
//// System.out.println(checkingAccount.withdraw(100));
// SavingsAccount savingsAccount = new SavingsAccount(1000);
//
// for (int i = 0; i < 5; i++) {
// int date = i+1;
// System.out.println("============第"+date+"月============");
// System.out.println(savingsAccount.Accountinfo());
// System.out.println(savingsAccount.earnMonthlylnterest(savingsAccount.getBalance()));
// System.out.println(savingsAccount.deposit(500));
// System.out.println(savingsAccount.withdraw(100));
// } // CheckingAccount checkingAccount = new CheckingAccount(1000);
// checkingAccount.deposit(10);//1010-1=1009
// System.out.println(checkingAccount.getBalance());
SavingsAccount savingsAccount = new SavingsAccount(1000);
savingsAccount.deposit(100);
savingsAccount.deposit(100);
savingsAccount.deposit(100);
System.out.println(savingsAccount.getBalance());//1300
savingsAccount.deposit(100);
System.out.println(savingsAccount.getBalance());//1400-1 = 1399 //月初,定时器自动调用earnMonthlylnterest
savingsAccount.earnMonthlylnterest();
System.out.println(savingsAccount.getBalance());//1399+13.99
savingsAccount.withdraw(100);//免手续费,1412.99-100
System.out.println(savingsAccount.getBalance());
savingsAccount.withdraw(100);
savingsAccount.withdraw(100);
System.out.println(savingsAccount.getBalance());//1412.99-200
savingsAccount.deposit(100);//扣手续费
System.out.println(savingsAccount.getBalance());//1211.99
}
} class BankAccount {
private double balance;
// public int fee = 1;
// Scanner scanner = new Scanner(System.in);
public BankAccount(double initialBalance){
this.balance = initialBalance;
} public void deposit(double amount){//存款
balance += amount;
} public void withdraw(double amount){//取出
balance -= amount;
} public String Accountinfo(){
return "账户当前金额: "+balance;
} public double getBalance() {
return balance;
} public void setBalance(double balance) {
this.balance = balance;
}
}

3.重写equals方法

编写Doctor类{name, age. job, gender, sal}以及相应的getter()和setter()方法,5个参数的构造器,

重写父类的equals()

方法:public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。

相等就是判断属性是否相同。

根据题意写出Doctor类

class Doctor{
private String name;
private int age;
private String job;
private char gender;
private double sal; public Doctor(String name, int age, String job, char gender, double sal) {
this.name = name;
this.age = age;
this.job = job;
this.gender = gender;
this.sal = sal;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getJob() {
return job;
} public void setJob(String job) {
this.job = job;
} public char getGender() {
return gender;
} public void setGender(char gender) {
this.gender = gender;
} public double getSal() {
return sal;
} public void setSal(double sal) {
this.sal = sal;
} @Override//重写equals,所有Object的子类都需要重写以满足特定的判定需求
public boolean equals(Object obj) {
//判断两个比较对象是否相同
if(this == obj){
return true;
}
//判断obj是否为Doctor类型或其子类
if(!(obj instanceof Doctor)){//不是的话
return false;
}
//如果相等就向下转型,因为obj的运行类型是Doctor或者其子类型
//要从需要比较的子类中获取所有属性并进行比较
Doctor doctor = (Doctor) obj;
return this.name.equals(doctor.name)&&this.age ==doctor.age&&
this.gender == doctor.gender&&this.job.equals(doctor.job)&&this.sal==doctor.sal;
}
}

注意,为什么要重写equals类呢?

实际上这是一个很常规的操作,java提供的父类Object中定义的equals仅仅能判断输入的两个对象的地址是否相同,即两个对象是否相同,并不能判断对象的具体类型(详见java源码)

因此开发者需要根据具体判断需求重写equals类,实际上java提供的数据类型在使用equals进行比较时,已经使用了针对相应类型重写的equals类了(例如在比较String时,其使用的equals类就不是Object中定义的equals)

测试类

public class Homework10 {
public static void main(String[] args) {
Doctor doctor1 = new Doctor("jk",20,"牙医",'男',2000);
Doctor doctor2 = new Doctor("jk",20,"牙医",'男',2000); System.out.println(doctor1.equals(doctor2));//ture
}
}

4.综合练习

题目
打印效果如下
/*
老师的信息:
姓名:王飞
年龄:30
性别:男
工龄:5
我承诺,我会认真教课。
王飞爱玩象棋
--------------------------
学生的信息:
姓名:小明
年龄:15
性别:男
学号:00023102
我承诺,我会好好学习。
小明爱玩足球。
*/
/*
* 案例题目描述;
(1)做一个Student类,Student类有名称(name),性别(sex),年龄(age).学号(stu_id),
* 做合理封装,通过构造器在创建对象时将4个属性赋值。
(2)写一个Teacher类,Teacher类有名称(name),性别(sex),年龄(age),工龄(work_age).
* 做合理封装,通过构造器在创建对象时将4个属性赋值。
(3)抽取一个父类Person类,将共同属性和方法放到Person类
(4)学生需要有学习的方法(study),在方法里写生“我承诺,我会好好学习。”。
(5)教师需要有教学的方法(teach),在方法里写上“我承诺,我会认真教学。“.
(6)学生和教师都有玩的方法(play),学会玩的是足球,老师玩的是象棋,此方法是返回字符串的,
* 分别返回“xx爱玩足球”和“双爱玩象棋”(其中xXx分别代表学生和老师的姓名)。
* 因为玩的方法名称都一样,听以要求此方法定义在父类中,子类实现重写。
* 应当分析出需要打印信息的方法
(7)定义多态数组,里面保存2个学生和2个教师,要求按年龄从高到低排序,
(8)定义方法,形参为Person类型,功能:调用学生的study或教师的teach方法
学生类

没什么好说的,就是按属性-构造器-get/set方法的流程写就行

public class Student extends Person{
//private String name;
//private char gender;
//private int age;
private String stu_id; public Student(String name, char gender, int age, String stu_id) {
super(name, gender, age);
this.stu_id = stu_id;
} public String getStu_id() {
return stu_id;
} public void setStu_id(String stu_id) {
this.stu_id = stu_id;
} public void study(){
System.out.println(getName()+"说,要好好学习");
} @Override
public String play() {
return super.play()+"足球";
}
//编写一个输出信息的方法,体现封装
public void printInfo(){
System.out.println("学生信息:");
System.out.println(super.basicInfo());
System.out.println("学号:"+stu_id);
study();
System.out.println(play());
} @Override
public String toString() {
return "Student{" +
"stu_id='" + stu_id + '\'' +
'}'+super.toString();
}
}
教师类
public class Teacher extends Person{
//private String name;
//private char gender;
//private int age;
private int work_age; public Teacher(String name, char gender, int age, int work_age) {
super(name, gender, age);
this.work_age = work_age;
} public int getWork_age() {
return work_age;
} public void setWork_age(int work_age) {
this.work_age = work_age;
} public void teach(){
System.out.println(getName()+"说,要认真教学");
} @Override
public String play() {
return super.play()+"象棋";
} //输出信息的方法
public void printInfo(){
System.out.println("老师的信息:");
System.out.println(super.basicInfo());
System.out.println("工龄:"+work_age);
teach();
System.out.println(play());
} @Override
public String toString() {
return "Teacher{" +
"work_age=" + work_age +
'}'+super.toString();
}
}

注意,按正常的逻辑来说,拿到需求后都是先把子类写出来(例如这里的学生和教师类),然后再去将他们共同的属性抽离写出父类(这里是Person)

父类Person

学生和教师类中共有的属性是姓名、年龄和性别,拿出来构成父类

public class Person {
private String name;
private char gender;
private int age; public Person(String name, char gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public char getGender() {
return gender;
} public void setGender(char gender) {
this.gender = gender;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} //编写play方法,把共有的输出内容写在这里
public String play(){
return name + "爱玩";
} //返回一个基本信息
/*
姓名:xx
年龄:x
性别:x
**/
public String basicInfo(){
return "姓名: "+name+"\n年龄: "+age+"\n性别: "+gender;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", age=" + age +
'}';
}
}

细节说明

1、学生的特殊方法是study,老师的是teach,然后他们都有一个爱好类play,只是打印的爱好不同,因此该类可以写在父类中,通过继承去使用,不同类在复用时有自定义内容

2、打印信息肯定需要一个打印类,该类也需要进行抽离,基本信息在父类打印【basicInfo()】,特殊信息在子类通过继承复用的方式打印【printInfo()】

主类

(7)定义多态数组,里面保存2个学生和2个教师,要求按年龄从高到低排序

​ 没什么好说的,排序就用冒泡就行【bubbleSort()】

(8)定义方法test,形参为Person类型,功能:调用学生的study或教师的teach方法

​ "形参为Person类型"又要调用子类方法,联想到对象类型判断【instanceof】和向下转型

以上两个需求在主类中编写方法实现

public class Homework13 {
public static void main(String[] args) {
//测试学生
Student student = new Student("xm", '男', 15, "00328");
student.printInfo();
//测试老师
Teacher teacher = new Teacher("zf", '男', 30, 15);
System.out.println("--------------------------------------------");
teacher.printInfo();
//定义多态数组,里面保存2个学生和2个老师,要求年龄从高到低
Person[] people = new Person[4];
people[0] = new Student("jk",'女',10,"001");
people[1] = new Student("km",'男',12,"002");
people[2] = new Teacher("SM",'男',35,5);
people[3] = new Teacher("xx",'男',23,1);
//创建对象
Homework13 homework13 = new Homework13();
homework13.bubbleSort(people);
//输出数组
System.out.println("-----------排序后的数组-----------");
for (int i = 0; i < people.length; i++) {
System.out.println(people[i]);
}
//遍历数组,调用test方法
System.out.println("=========");
for (int i = 0; i < people.length; i++) {
homework13.test(people[i]);
}
}
//定义方法,形参为Person类型,功能:调用学生的study和老师的teach方法
//向下转型和类型判断
public void test(Person p){
if(p instanceof Student){
((Student)p).study();
} else if (p instanceof Teacher) {
((Teacher)p).teach();
}else {
System.out.println("do nothing");
}
}
//方法,完成年龄从高到低排序
public void bubbleSort(Person[] people){
Person temp = null;
for (int i = 0; i < people.length-1; i++) {
for (int j = 0; j < people.length-1-i; j++) {
//判断条件
if(people[j].getAge()<people[j+1].getAge()){
temp = people[j];
people[j] = people[j+1];
people[j+1] = temp;
}
}
}
}
}

【Java复健指南08】OOP中级03【完结】-Object类和一些练习的更多相关文章

  1. 【Java复健指南09】项目练习全解--房屋出租系统

    一个基于文本界面的综合练习,主要用于串联和回忆知识点,比较简单 各个界面的设计样式 主菜单 =============房屋出租系统菜单============ 1 新 增 房 源 2 查 找 房 屋 ...

  2. 【Java复健指南15】链表LinkedList及其说明

    链表LinkedList by Java 之前有写过一些记录(引用),但是忘了乱了,现在重新梳理一遍 链表是Java中List接口的一种实现 定义(引用) 链表(linked list)是一种物理存储 ...

  3. 别样JAVA学习(五)继承上(1.0)Object类equals()

    上一节继承下(一)我们进行抽象类.接口以及多态的学习. 接下来大家我们讲点特殊的东西就是object类, 我们一直在说继承,子继承了父,父还有没有父类呢, 为什么这么思考,大家想构造函数的第一行是不是 ...

  4. 别样JAVA学习(五)继承上(1.1)Object类toString()

    接下来说完equals以后,我们学习接下来的toString(), Java又觉得全部对象不光具有比較性, 还能使对象变成字符串被打印. 出现 曾经前面显示的是数组.如今显示的是这个对象所属的类. 紧 ...

  5. Java基础知识强化26(1):Object类之Object类的概述

    1.Object类 类Object是类层次结构的根类,每个类都使用 Object作为超类.所有对象(包括数组)都实现这个类的方法 每个类直接或者间接继承自Object类   2.Object类无参构造 ...

  6. 【系列】Java多线程初学者指南(1):线程简介

    原文地址:http://www.blogjava.net/nokiaguy/archive/2009/nokiaguy/archive/2009/03/archive/2009/03/19/26075 ...

  7. 菜鸡的Java笔记 Object 类

    Object 类        Object类 的主要作用        Object 类的常用方法             内容        虽然有了对象的向上转型,可以解决了参数的统一问题,但是 ...

  8. java 常用类库:Object类和Objects类

    1,Object类: Object类是所有的类,数组,枚举的父类,也就是说,JAVA中允许把任何的对象赋值给Object类(包括基础数据类型),当定义一个类的时候,没有使用extends关键字显示指定 ...

  9. Java工程师学习指南 中级篇

    Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...

  10. Java工程师学习指南(中级篇)

    Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...

随机推荐

  1. [转帖]一个故事看懂CPU的SIMD技术

    https://www.cnblogs.com/xuanyuan/p/16048303.html 好久不见,我叫阿Q,是CPU一号车间的员工.我所在的CPU有8个车间,也就是8个核心,咱们每个核心都可 ...

  2. [转帖]Cat导致内存不足原因分析

    背景 线上几亿的数据在回刷的时候容器服务会出现OOM而重启,导致任务中断 内存泄露分析 jmap -histo pid 找出了有几十亿的java.lang.StackTraceElement对象,找不 ...

  3. [转帖]记录自己安装内存带宽测试工具——Stream过程

    测试环境: CPU:Kunpeng 920 8Core MEM:16G Storage:200G OS:openEuler 20.03 (LTS-SP3) 1 服务器资源监控工具--Stream 1. ...

  4. Linux 开启防火墙 避免非干系人误操作的处理

    公司里面进行系统集成测试. 不想让开发能够更改我的服务器信息, 但是改密码又太麻烦了. 想了想还是用 防火墙好一些. 第一步 开启防火墙 systemctl enable firewalld syst ...

  5. 计划任务方式定期获取jvm dump的方法

    说明 产品最近有一些问题,想着能够每隔一段时间抓取一下dump文件. 需求 可以定期抓取, 需要注意磁盘空间的使用. 实现方法 定时任务使用 crontab 计划任务来做 预定义获取jvm dump的 ...

  6. 下载 ingres-nginx

    https://quay.io/repository/kubernetes-ingress-controller/nginx-ingress-controller-arm64?tag=latest&a ...

  7. Vue中this.$options.data()和this.$data知多少?

    1.场所描述 如何获取vue-data中的所有值? 如何获取vue-data中的某一个值? 如何获取vue-data中的初始值? 如何设置data中的值位初始值? 2.主角登场 this.$optio ...

  8. 『深度学习项目四』基于ResNet101人脸特征点检测

    相关文章: [深度学习项目一]全连接神经网络实现mnist数字识别 [深度学习项目二]卷积神经网络LeNet实现minst数字识别 [深度学习项目三]ResNet50多分类任务[十二生肖分类] 『深度 ...

  9. 驱动开发:DKOM 实现进程隐藏

    DKOM 就是直接内核对象操作技术,我们所有的操作都会被系统记录在内存中,而驱动进程隐藏的做旧就是操作进程的EPROCESS结构与线程的ETHREAD结构.链表,要实现进程的隐藏我们只需要将某个进程中 ...

  10. 由刷题学习 heapq

    今日一题是 面试题 17.14. 最小K个数 https://leetcode-cn.com/problems/smallest-k-lcci/ 还好 提示 0 <= len(arr) < ...