第八章面向对象编程(中级)

8.1访问修饰符
8.1.1基本介绍
java提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):

  1. 公开级别:用 public 修饰,对外公开
  2. 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开. 4) 私有级别:用 private 修饰,只有类本身可以访问,不对外公开.

4种访问修饰符的访问范围
在这里插入图片描述
使用的注意事项
在这里插入图片描述
8.2面向对象编程三大特征
8.2.1基本介绍
面向对象编程有三大 特征:封装,继承,和多态

封装:encapsulation就是把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授予的操作【方法】,才能对数据进行操作。

8.2.2封装的理解和好处
在这里插入图片描述
8.2.3封装的实现步骤(三步)
在这里插入图片描述
8.3快速入门
在这里插入图片描述
代码略
可以将构造器和setXxx结合

//有三个属性的构造器
public Person(String name, int age, double salary) {
	// this.name = name;
	// this.age = age;
	// this.salary = salary;
	//我们可以将 set 方法写在构造器中,这样仍然可以验证
	setName(name);
	setAge(age);
	setSalary(salary);
}

setXxx方法中可以设置一些约束
例如:

//姓名(长度为 2 位 3 位或 4 位)
public void setName(String name) {
	if (name.length() >= 2 && name.length() <= 4) {
	this.name = name;
	} else {
	System.out.println("姓名要求(长度为 2 位 3 位或 4 位),默认值 无名");
	this.name = "无名";
	}
}

//余额(必须>20)
public void setBalance(double balance) {
	if (balance > 20) {
	this.balance = balance;
	} else {
	System.out.println("余额(必须>20) 默认为 0");
	}
}

//密码(必须是六位)
public void setPwd(String pwd) {
	if (pwd.length() == 6) {
	this.pwd = pwd;
	} else {
	System.out.println("密码(必须是六位)默认密码为 000000");
	this.pwd = "000000";
	}
}

8.4面向对象编程-继承
8.4.1为什么需要继承?
在这里插入图片描述
8.4.2继承基本介绍和示意图
在这里插入图片描述
8.4.3继承的基本语法
在这里插入图片描述
8.4.4继承给编程带来的便利

  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了

8.4.5继承的深入讨论/细节问题
在这里插入图片描述
在这里插入图片描述
输入 ctrl + H 可以看到类的继承关系

8.5继承的本质分析
在这里插入图片描述

package com.hspedu.extend_;
/**
* 讲解继承的本质
*/
public class ExtendsTheory {
	public static void main(String[] args) {
		Son son = new Son();//内存的布局
		//?-> 这时请大家注意,要按照查找关系来返回信息
		//(1) 首先看子类是否有该属性
		//(2) 如果子类有这个属性,并且可以访问,则返回信息
		//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
		//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object... System.out.println(son.name);//返回就是大头儿子
		//System.out.println(son.age);//返回的就是 39
		//System.out.println(son.getAge());//返回的就是 39
		System.out.println(son.hobby);//返回的就是旅游
	}
}
class GrandPa { //爷类
	String name = "大头爷爷";
	String hobby = "旅游";
}
class Father extends GrandPa {//父类
	String name = "大头爸爸";
	private int age = 39;
	public int getAge() {
		return age;
	}
}
class Son extends Father { //子类
	String name = "大头儿子";
}

子类创建的内存布局
在这里插入图片描述
课堂练习:
在这里插入图片描述
8.6super关键字
8.6.1基本介绍
super代表父类的引用,用于访问父类的属性、方法、构造器
8.6.2基本语法
在这里插入图片描述
super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用 super 去访问爷爷类的成员;
如果多个基类(上级类)中都有同名的成员,使用 super 访问遵循就近原则。A->B->C

super().xx和this.xx:
找xx 和 this.xx()),顺序是:
(1)先找本类,如果有,则调用
(2)如果没有,则找父类(如果有,并可以调用,则调用)
(3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类
// 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
xx 和 thisxx 查找的规则是
(1) 先找本类,如果有,则调用
(2) 如果没有,则找父类(如果有,并可以调用,则调用)
(3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object 类

super给编程带来的便利/细节
在这里插入图片描述
super和this的比较
在这里插入图片描述
8.7方法重写/覆盖(override)
8.7.1基本介绍
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么就说子类的这个方法覆盖了父类的方法。

8.7.2注意事项和使用细节
方法重写也叫方法覆盖,需要 满足以下条件:
在这里插入图片描述
方法重载和重写的比较:
在这里插入图片描述
8.8面向对象编程-多态
8.8.1多[多种]态[状态]基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
1)方法的多态
重写和重载就体现多态

package com.hspedu.poly_;
public class PloyMethod {
	public static void main(String[] args) {
		//方法重载体现多态
		A a = new A();
		//这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
		System.out.println(a.sum(10, 20));
		System.out.println(a.sum(10, 20, 30));
		//方法重写体现多态
		B b = new B();
		a.say();
		b.say();
		}
}
class B { //父类
	public void say() {
		System.out.println("B say() 方法被调用...");
	}
}
class A extends B {//子类
	public int sum(int n1, int n2){//和下面 sum 构成重载
		return n1 + n2;
		}
		public int sum(int n1, int n2, int n3){
		return n1 + n2 + n3;
		}
		public void say() {
		System.out.println("A say() 方法被调用...");
	}
}

2)对象的多态
重点注意:
1)一个对象的编译类型和运行类型可以不一致;
2)编译类型在定义对象时,就可以确定了,不能改变;
3)运行类型是可以改变的;
4)编译类型看定义时=号的左边,运行类型看=号的右边。
例子:
在这里插入图片描述

public class PolyObject {
	public static void main(String[] args) {
		//体验对象多态特点
		//animal 编译类型就是 Animal , 运行类型 Dog
		Animal animal = new Dog();
		//因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry 就是 Dog 的 cry
		animal.cry(); //小狗汪汪叫
		//animal 编译类型 Animal,运行类型就是 Cat
		animal = new Cat();
		animal.cry(); //小猫喵喵叫
	}
}

8.8.2多态注意事项和细节讨论
在这里插入图片描述
√属性没有重写之说!属性的值看编译类型
√instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型

public static void main(String[] args) {
	//向上转型: 父类的引用指向了子类的对象
	//语法:父类类型引用名 = new 子类类型();
	Animal animal = new Cat();
	Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类
	//多态的向下转型
	//(1)语法:子类类型 引用名 =(子类类型)父类引用;
	//问一个问题? cat 的编译类型 Cat,运行类型是 Cat
	Cat cat = (Cat) animal;
	cat.catchMouse();//猫抓老鼠
	//(2)要求父类的引用必须指向的是当前目标类型的对象
	}
}

课堂练习:
在这里插入图片描述
8.8.2java的动态绑定机制
1)当调用对象方法 的时候,该方法会和该对象的内存地址/运行类型绑定
2)当调用对象属性时,没有动态绑定机制,哪里申明,哪里使用

8.8.3多态的应用
1)多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象和 2 个Teacher 对象, 统一放在数组中,并调用每个对象的say 方法.
应用实例升级:如何调用子类特有的方法,比如Teacher 有一个 teach , Student 有一个 study怎么调用?

public class PloyArray {
	public static void main(String[] args) {
		//应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、
		// 2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法
		Person[] persons = new Person[5];
		persons[0] = new Person("jack", 20);
		persons[1] = new Student("mary", 18, 100);
		persons[2] = new Student("smith", 19, 30.1);
		persons[3] = new Teacher("scott", 30, 20000);
		persons[4] = new Teacher("king", 50, 25000);
		//循环遍历多态数组,调用 say
		for (int i = 0; i < persons.length; i++) {
			//老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判断
			System.out.println(persons[i].say());//动态绑定机制
			//这里大家聪明. 使用 类型判断 + 向下转型. if(persons[i] instanceof Student) {//判断 person[i] 的运行类型是不是 Student
			Student student = (Student)persons[i];//向下转型
			student.study();
			//小伙伴也可以使用一条语句 ((Student)persons[i]).study();
			} else if(persons[i] instanceof Teacher) {
				Teacher teacher = (Teacher)persons[i];
				teacher.teach();
			} else if(persons[i] instanceof Person){
			//System.out.println("你的类型有误, 请自己检查...");
			} else {
				System.out.println("你的类型有误, 请自己检查...");
			}
		}
	}
}

2)多态数组
在这里插入图片描述
8.9Object类详解
8.9.1equals方法
在这里插入图片描述
8.9.2如何重写equals方法

//重写 Object 的 equals 方法
public boolean equals(Object obj) {
	//判断如果比较的两个对象是同一个对象,则直接返回 true
	if(this == obj) {
	return true;
	}
	//类型判断
	if(obj instanceof Person) {//是 Person,我们才比较
	//进行 向下转型, 因为我需要得到 obj 的 各个属性
	Person p = (Person)obj;
	return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
	}
	//如果不是 Person ,则直接返回 false
	return false;
}

8.9.3hashCode方法
在这里插入图片描述
在这里插入图片描述
8.9.4toString方法

  1. 基本介绍
    默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】
    子类往往重写 toString 方法,用于返回对象的属性信息
  2. 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式.
  3. 当直接输出一个对象时,toString 方法会被默认的调用
    重写 toString 方法, 输出对象的属性使用快捷键即可 alt+insert -> toString

8.9.5finalize方法

  1. 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法
  2. 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法。
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制

8.10断点调试
在断点调试过程中,是运行状态,是以对象的运行类型来执行的
快捷键:
F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)
F7:跳入方法内
F8: 逐行执行代码. shift+F8: 跳出方法

零钱通项目
重点:代码思想
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
化繁为简.

  1. 先完成显示菜单,并可以选择
  2. 完成零钱通明细.
  3. 完成收益入账
  4. 消费
  5. 退出
package myself.smallchange.oop;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class Mainmenuoop {
    //相关变量
    boolean loop = true;//是否循环显示
    Scanner scanner = new Scanner(System.in);
    String key = "";

    double money = 0;
    double balance = 0;//余额

    String detail = "-----------零钱通菜单-----------";
    Date date = null;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    String note = "";

    String hint = "";

    //查看零钱通明细
    public void showDetail(){
        System.out.println(detail);
    }

    //收益入账
    public void earn(){
        System.out.print("收益入账金额:");
        money = scanner.nextDouble();
        if(money <= 0){
            System.out.println("收益入账金额输入错误!");
            return;//退出方法不再执行后面的代码
        }
        balance += money;
        date = new Date();//获取当前日期
        //拼接收益入账信息到detail
        detail += String.format("\n收益入账\t+" + money + "\t"
                + sdf.format(date) + "\t" + "余额:" + balance );
    }

    //消费
    public void spend(){
        System.out.print("消费备注:");
        note = scanner.next();
        System.out.print("消费金额:");
        money = scanner.nextDouble();
        //如果消费金额小于等于0,或者余额不够就提示消费金额输入错误
        if(money <= 0 || balance < money){
            System.out.println("消费金额输入错误!");
            return;
        }
        balance -= money;
        date = new Date();//获取当前日期
        //拼接消费入账信息到detail
        detail += String.format("\n" + note + "\t\t-" + money + "\t"
                + sdf.format(date) + "\t" + "余额:" + balance );
    }

    //退出
    public void exit(){
        //定义一个choice,接收用户的输入
        //(1)使用while+break来处理接收到的输入是y或者n
        //(2)退出while后,再判断choice是y还是n,就可以决定是否退出
        while (true){
            //用户必须输入y/n,否则就一直循环
            System.out.println("你确定要退出嘛(y/n)?");
            hint = scanner.next();
            if ("y".equals(hint) || "n".equals(hint)){
                break;
            }
        }
        if (hint.equals("y")){
            loop = false;
            System.out.println("您已经退出零钱通。");
        }
    }

    //主菜单
    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.print("请选择(1-4):");
            key = scanner.next();

            switch (key){
                case "1" :
                    showDetail();
                    break;
                case "2" :
                    earn();
                    break;
                case "3" :
                    spend();
                    break;
                case "4" :
                    exit();
                    break;
                default:
                    System.out.println("输入有误,请重新选择!");
                    break;
            }
        }while (loop);

    }

}



package myself.smallchange.oop;

public class smallchangeoop {
    public static void main(String[] args) {
        Mainmenuoop mainmenuoop = new Mainmenuoop();
        mainmenuoop.mainMenu();
    }
}

总结:
1.return;和break;作业没有记清楚
2.swich(){
case " " :
结构
3.Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm”);
data = new Data()
使用 sdf.format(data);
日期,和日期格式化
4.拼接信息的思想
5.while (true){
//用户必须输入y/n,否则就一直循环
System.out.println(“你确定要退出嘛(y/n)?”);
hint = scanner.next();
if (“y”.equals(hint) || “n”.equals(hint)){
break;
}
}
反向限制,考虑不符合的情况,简化代码
一个功能用一个模块来实现,方便以后扩展

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值