Java-11-面向对象三大特性之继承性

16. 面向对象三大特性之继承性

面向对象的三大特征:封装、继承、多态

继承是多态的前提,如果没有继承,就没有多态。

在继承的关系中,”子类就是一个父类“。也就是说,子类可以被当作父类看待。

例如父类是员工,子类是讲师,那么”讲师就是一个员工“。

Java语言是单继承的。一个类的直接父类只能由唯一一个。

但是,Java语言可以多级继承。

一个子类的直接父类是唯一的,但是一个父类可以由多个子类。

image-20211210164118381

16.1 继承的基本格式

定义父类格式:(一个普通的类定义)

public class 父类名称{
// ...
}

定义子类的格式:

public class 子类名称 extends 父类名称{
// ...
}

Employee类

package com.tipdm.demo01;

// 定义一个父类
public class Employee {
    public void method(){
        System.out.println("方法执行!");
    }
}

Teacher类

package com.tipdm.demo01;

// 定义了一个员工的子类:讲师
public class Teacher extends Employee{
}

Assistant类

package com.tipdm.demo01;

// 定义一个子类:助教
public class Assistant extends Employee{
}

主类:

package com.tipdm.demo01;

/**
 * 面向对象的三大特征:封装、继承、多态
 * 继承是多态的前提,如果没有继承,就没有多态。
 *
 * 在继承的关系中,”子类就是一个父类“。也就是说,子类可以被当作父类看待。
 * 例如父类是员工,子类是讲师,那么”讲师就是一个员工“。关系:is-a。
 *
 * 定义父类格式:(一个普通的类定义)
 * public class 父类名称{
 *     // ...
 * }
 *
 * 定义子类的格式:
 * public class 子类名称 extends 父类名称{
 *     // ...
 * }
 */
public class demo1 {
    public static void main(String[] args) {
        // 创建一个子类对象:讲师
        Teacher teacher1 = new Teacher();
        // Teacher类当中虽然什么都没写,但是会继承来自Employee的方法。
        teacher1.method();

        // 创建一个子类对象:助教
        Assistant assistant1 = new Assistant();
        // Assistant类当中虽然什么都没写,但是会继承来自Employee的方法。
        assistant1.method();
    }
}

16.2 继承后的特点

父类

package com.tipdm.demo02;

public class Fu {
    int numFu = 10;
    int num = 100;

    public void methodFu(){
        // 使用的是本类当中的,不会向下找子类的。
        System.out.println(num);
    }
}

子类

package com.tipdm.demo02;

public class Zi extends Fu{
    int numZi = 20;

    int num = 200;

    public void methodZi(){
        // 因为本类当中有num,所以这里用的是本类的num
        System.out.println(num);
    }
}

主类:

package com.tipdm.demo02;

/**
 * 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
 * 直接通过子类对象访问成员变量:
 *      等号左边是谁,就有限用谁,没有则向上找。
 * 间接通过成员方法访问成员变量:
 *      该方法属于谁,就优先用谁,没有则向上找。
 */
public class demo1 {
    public static void main(String[] args) {
        Fu fu = new Fu();  // 创建父类对象
        System.out.println(fu.numFu);  // 10 只能使用父类的东西,没有任何子类的内容

        System.out.println("================");
        Zi zi = new Zi();
        System.out.println(zi.numFu);  // 10
        System.out.println(zi.numZi);  // 20
        System.out.println("================");

        System.out.println(zi.num);  // 如果父类中出现同名变量,以子类为主
//        System.out.println(zi.abc);  // 不存在则编译报错
        System.out.println("================");

        // 这个方法是子类的,优先用子类的,没有再向上找
        zi.methodZi();  // 200
        // 这个方法是在父类中定义的,优先使用父类中的num
        zi.methodFu();
    }
}

16.3 继承后变量的访问规则

父类

package com.tipdm.demo03;

public class Fu {
    int num = 10;
}

子类

package com.tipdm.demo03;

public class Zi extends Fu{
    int num = 20;

    public void method(){
        int num = 30;
        System.out.println(num);  // 局部变量
        System.out.println(this.num);  // 本类的成员变量
        System.out.println(super.num);  // 父类的成员变量
    }
}

主类

package com.tipdm.demo03;

/**
 * 局部变量:直接写
 * 本类的成员变量:this.成员变量名
 * 父类的成员变量:super.成员变量名
 */
public class demo1 {
    public static void main(String[] args) {
        Zi zi = new Zi();

        zi.method();
    }
}

16.4 继承后方法的访问规则

父类

package com.tipdm.demo04;

public class Fu {
    public void methodFu(){
        System.out.println("父类方法执行!");
    }

    public void method(){
        System.out.println("父类重名方法执行!");
    }
}

子类

package com.tipdm.demo04;

public class Zi extends Fu{
    public void methodZi(){
        System.out.println("子类方法执行!");
    }

    public void method(){
        System.out.println("子类重名方法执行!");
    }
}

主类:

package com.tipdm.demo04;

/**
 * 在父子类的继承关系中,创建子类对象,访问成员方法的规则:
 *      创建的对象是谁,就优先用谁,如果没有则向上找
 *
 * 注意事项:
 * 无论是成员方法还是成员变量,如果没有都是向上找父类,绝不会向下找子类的。
 * 重写(Override)
 * 概念:在继承关系中,当方法的名称一样,参数列表也一样。
 * 重写(Overrie): 方法的名称【一样】,参数列表【也一样】。覆盖、覆写。
 * 重载(Overload): 法的名称【一样】,参数列表【不一样】。
 *
 * 方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
 */
public class demo1 {
    public static void main(String[] args) {
        Zi zi = new Zi();

        zi.methodFu();
        zi.methodZi();

        // 创建的是new了子类对象,所以优先用子类方法
        zi.method();
    }

}

16.5 继承之重写(Override)

父类

package com.tipdm.demo05;

public class Fu {
    public void method(){
        System.out.println("父类方法!");
    }
}

子类

package com.tipdm.demo05;

public class Zi extends Fu{
    @Override
    public void method(){
        System.out.println("子类方法!");
    }
}

主类

package com.tipdm.demo05;

/**
 * 方法覆盖重写的注意事项:
 * 1. 必须保证父子类之间方法相同,参数列表也相同。
 * @Override:写在方法前面,用来检验是不是有效的正确覆盖重写,如果写在方法前面没有报错说明是有效的覆盖重写。
 * 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。
 * 2. 子类方法的返回值必须小于等于父类的返回值范围。
 * java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就算Object的子类
 * 父类返回Object,子类返回String是正确写法。
 * 父类返回String,子类返回Object是错误写法。
 * 3. 子类方法的权限必须大于等于父类方法的权限修饰符。
 * 小扩展提示:public > protected > (default) > private
 * 备注:(default)不是关键字default,而是什么都不写,留空
 */
public class demo1 {
    public static void main(String[] args) {

    }
}

复用父类的方法

父类

package com.tipdm.demo06;

// 本来的老款手机
public class Phone {
    public void call(){
        System.out.println("打电话!");
    }

    public void send(){
        System.out.println("发短信!");
    }

    public void show(){
        System.out.println("显示号码");
    }
}

子类

package com.tipdm.demo06;

public class NewPhone extends Phone{
    @Override
    public void show() {
        super.show();  // 把父类的show方法拿过来重复利用
        // 自己子类再添加
        System.out.println("显示姓名");
        System.out.println("显示头像");
    }
}

主类

package com.tipdm.demo06;

public class demo1 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.call();
        phone.send();
        phone.show();
        System.out.println("==============");

        NewPhone newPhone = new NewPhone();
        newPhone.call();
        newPhone.send();
        newPhone.show();
    }
}

16.6 父子类构造方法访问特点

父类

package com.tipdm.demo07;

public class Fu {
    public Fu(){
        System.out.println("父类无参构造方法");
    }
    public Fu(int num){
        System.out.println("父类有参构造方法");
    }
}

子类

package com.tipdm.demo07;

public class Zi extends Fu{
    public Zi(){
//        super();  // 在调用父类无参构造方法
        super(10);  // 调用父类重载的构造方法
        System.out.println("子类构造方法!");
    }
//    public void method(){
//        super();  // 错误写法!只有子类构造方法,才能调用父类构造方法!。
//    }
}

主类

package com.tipdm.demo07;

/**
 * 继承关系中,父子类构造方法访问特点:
 * 1. 子类构造方法中,有一个默认隐含的“super()”调用,所以一定是先调用父类的构造方法,再调用子类的构造方法。
 * 2. 可以通过super关键字来子类构造调用父类重载构造。
 * 3. super的父类构造调用,必须是自来构造方法的第一个语句。不能一个子类构造调用多次super构造。
 *
 * 总结:
 * 子类必须调用父类构造方法,不写则赠送super(); 写了则用写的指定的super调用,super只能有一个,还必须是第一个。
 */
public class demo1 {
    public static void main(String[] args) {
        Zi zi = new Zi();
    }
}

16.7 super关键字的三种用法

父类

package com.tipdm.demo08;

public class Fu {
    int num = 10;

    public Fu(){
        System.out.println("父类的无参构造方法!");
    }
    public Fu(int num){
        System.out.println("父类的有参构造方法!");
    }

    public void methodFu(){
        System.out.println(num);
    }
}

子类

package com.tipdm.demo08;

public class Zi extends Fu{
    int num = 20;

    public Zi(){
        super(12);
    }

    public void methodZi(){
        super.methodFu();  // 访问父类的成员方法
        System.out.println(super.num);  // 访问父类的成员变量
    }
}

主类

package com.tipdm.demo08;

/**
 * super关键字的用法有三种:
 * 1. 在子类的成员方法中,访问父类的成员变量
 * 2. 在子类的成员方法中,访问父类的成员方法
 * 3. 在子类的构造方法中,访问父类的构造方法
 */
public class demo1 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println("============");
        zi.methodZi();
    }
}

16.8 this关键字的三种用法

父类

package com.tipdm.demo09;

public class Fu {
    int num = 30;
}

子类

package com.tipdm.demo09;

public class Zi extends Fu{
    int num = 20;

    public Zi(){
//        super();  // 错误写法
        this(123);  // 本类的无参构造,调用本类的有参构造
//        this(12, 123);  // 错误写法
    }

    public Zi(int n){
        this(12, 13);
    }

    public Zi(int m, int n){}

    public void method(){
        int num = 10;
        System.out.println(num);  // 局部变量
        System.out.println(this.num);  // 本类中的成员变量
        System.out.println(super.num);  // 父类中的成员变量

        this.showMessage();
    }

    public void showMessage(){
        System.out.println("本类中的另外一个成员方法!");
    }
}

主类

package com.tipdm.demo09;

/**
 * super关键字用来访问父类内容,而this关键字用来访问本类内容。用法也有三种:
 * 1. 在本类的成员方法中,访问本类的成员变量。
 * 2. 在本类的成员方法中,访问本类中的另一个成员方法。
 * 3. 在本类的构造方法中,访问本类中的另一个构造方法。
 * 在第三种用法当中要注意:
 * A. this(...)调用也必须是构造方法的第一个语句,唯一一个。
 * B. this和super只能一个放在狗仔方法的第一个语句。
 */
public class demo1 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}

16.9 抽象方法和抽象类

image-20211210164054220

抽象父类

package com.tipdm.demo10;

/**
 * 抽象方法:就算加上abstract关键字,然后去掉大括号,直接分号结束
 * 抽象类:抽象方法所在的类,必须是抽象类才行.在class之前写上abstract即可.
 *
 * 如何使用抽象类和抽线方法:
 * 1. 不能直接创建new抽象对象.
 * 2. 必须用一个子类继承抽象类.
 * 3. 子类必须覆盖重写抽象父类中所有的抽象方法.
 * 覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号.
 * 4. 创建子类对象进行使用
 *
 * 注意事项:
 * 1.
 */
public abstract class Animal {
    public abstract void eat();
}

子类

package com.tipdm.demo10;

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("吃鱼!");
    }
}

主类

package com.tipdm.demo10;

public class demo1 {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        cat1.eat();
    }
}

16.10 抽象类的构造方法

父类

package com.tipdm.demo11;

public abstract class Fu {
    public Fu(){
        System.out.println("抽象父类构造方法执行!");
    }
    public abstract void eat();
}

子类

package com.tipdm.demo11;

public class Zi extends Fu{

    public Zi(){
        // super();
        System.out.println("子类构造方法执行!");
    }

    @Override
    public void eat() {
        System.out.println("吃饭饭");
    }
}

主类

package com.tipdm.demo11;

public class demo1 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.eat();
    }
}

注意事项:

  • 一个抽象类不一定含有抽象方法, 只要保证抽象方法所在的类是抽象类,即可.
  • 这样没有抽象方法的抽象类,也不能直接创建对象,在一些特殊场景下有用途.
public abstract class MuAbstract {
}

16.11 抽象类的继承

父类

package com.tipdm.demo12;

// 最高的抽象父类
public abstract class Animal {
    public abstract void sleep();

    public abstract void eat();
}

二级父类

package com.tipdm.demo12;

public abstract class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    // public abstract void sleep();  这个抽象方法没有重写导致子类也应该为抽象类
}

子类1

package com.tipdm.demo12;

public class Dog2ha extends Dog{
    @Override
    public void sleep() {
        System.out.println("hehehehe~~");
    }
}

子类2

package com.tipdm.demo12;

public class DogGolden extends Dog{
    @Override
    public void sleep() {
        System.out.println("呼呼呼....");
    }
}

主类

package com.tipdm.demo12;

public class demo {
    public static void main(String[] args) {
//        Animal animal = new Animal();  // 错误写法,抽象类无法直接new创建
//        Dog dog = new Dog(); // 由于Dog类中仍然存在抽象方法,故Dog类也为抽象类,同样无法直接创建
        Dog2ha dog2ha = new Dog2ha();
        dog2ha.eat();
        dog2ha.sleep();
        System.out.println("================");

        DogGolden dogGolden = new DogGolden();
        dogGolden.eat();
        dogGolden.sleep();
    }
}

16.12 题目:群主发红包

群主发普通红包.某群有多名成员,群主给成员发普通红包.

  • 普通红包规则:
    1. 群主的一笔金额,从群主余额中扣除,平均分成n等份,让成员领取.
    1. 成员领取红包后,保存到成员余额中.

image-20211210164447406

User类

package com.tipdm.demo13;

public class User {
    private String name;
    private int money;

    public void show(){
        System.out.println("我是:" + this.name + ",我有多少钱:" + this.money);
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public User(String name, int money) {
        this.name = name;
        this.money = money;
    }

    public User() {
    }
}

Manager类

package com.tipdm.demo13;

import java.util.ArrayList;

public class Manager extends User{
    public Manager(){

    }
    public Manager(String name, int money) {
        super(name, money);
    }

    // 发红包
    public ArrayList<Integer> send(int totalMoney, int count){
        // 设置一个数据用来存储发出去的红包
        ArrayList<Integer> RPList = new ArrayList<>();
        // 获取用户余额
        int restMoney = super.getMoney();
        // 判断一下,剩下的钱是否够发红包
        if(totalMoney > restMoney){
            System.out.println("余额不足!");
            return RPList;
        }
        // 开始发红包
        // 扣钱
        super.setMoney(restMoney - totalMoney);
        // 计算每个红包应该发多少钱,有可能除不尽,把余数也拿上
        int RP = totalMoney / count;
        int rest = totalMoney % count;
        // 装红包
        for (int i = 0; i < count - 1; i++) {
            RPList.add(RP);
        }
        RPList.add(RP + rest);  // 如果有余数就把剩下的钱全部放入最后一个红包
        return RPList;
    }
}

member类

package com.tipdm.demo13;

import java.util.ArrayList;
import java.util.Random;

public class Member extends User{
    public Member(){

    }

    public Member(String name, int money) {
        super(name, money);
    }

    public void get(ArrayList<Integer> RPList){
        // 判断一下红包池中是否还有红包
        if (RPList.size() == 0){
            System.out.println("*红包数量不够,[" + super.getName() + "]未抢到红包!");
        }else {
            // 抽取一个红包编号
            int index = new Random().nextInt(RPList.size());
            // 获取红包,并将该红包从红包池中移除
            Integer rp = RPList.remove(index);
            // 将获取到的红包放入余额
            int restMoney = super.getMoney();
            super.setMoney(restMoney + rp);
        }
    }
}

主类

package com.tipdm.demo13;

import java.util.ArrayList;

/**
 * 群主发普通红包.某群有多名成员,群主给成员发普通红包.
 * 普通红包规则:
 * 1. 群主的一笔金额,从群主余额中扣除,平均分成n等份,让成员领取.
 * 2. 成员领取红包后,保存到成员余额中.
 */
public class demo1 {
    public static void main(String[] args) {
        Manager manager = new Manager("群主", 100);
        Member member1 = new Member("员工1", 0);
        Member member2 = new Member("员工2", 0);
        Member member3 = new Member("员工3", 0);
        Member member4 = new Member("员工4", 0);
        // 展示各用户余额
        manager.show();
        member1.show();
        member2.show();
        member3.show();
        member4.show();
        System.out.println("=========== 开始发送红包 ===========");
        // 开始发红包
        ArrayList<Integer> RPList = manager.send(50, 4);
        member1.get(RPList);
        member2.get(RPList);
        member3.get(RPList);
        member4.get(RPList);
        System.out.println("=========== 红包发送结束 ===========");
        manager.show();
        member1.show();
        member2.show();
        member3.show();
        member4.show();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值