学习笔记--Java面向对象的继承

Java面向对象的继承

继承

  • 继承是面向对象的三大特性之一

  • 继承基本作用:代码复用;重要作用:有了继承才能有以后的“方法的覆盖”和“多态”

  • 继承语法格式:

      [修饰符列表] class 类名 extends 父类名{
          类体
      }
    
  • Java语言当中的继承只支持单继承

  • 术语:

    B类继承A类,其中:

    • A类称为:父类、基类、超类、superclass
    • B类称为:子类、派生类、subclass
  • Java语言中子类继承父类:

    • 私有的不支持
    • 构造方法不支持
    • 其他数据都可以被继承
  • Java语言中假设没有显示的继承任何类,默认继承JavaSE库提供的java.lang.Object类

public class ExtendsTest01 {

    public static void main(String[] args) {

        C c1 = new C();

        c1.doSome();    // 这里调用的doSome方法是从B类中继承的
    }
}

class A{
    public void doSome() {
        System.out.println("do some !");
    }
}

class B extends A{

}

class C extends B{

}

方法的覆盖

【回顾】Java中的·方法重载:

  • 方法重载称为Overload

  • 什么时候能用

    在同一个类当中,方法完成功能相似,建议方法同名

  • 什么样条件构成方法重载

    • 在同一个类当中
    • 方法名相同
    • 参数列表不同:类型、顺序、个数
  • 方法重载与什么无关

    • 方法的返回值类型无关
    • 方法的修饰符列表无关

【正片】方法覆盖

  • 方法覆盖【override官方】又被称作方法重写【overwrite】

  • 什么时候使用方法覆盖

    当父类中的方法已经无法满足当前子类的需求,子类有必要将父类中继承的方法进行重新编写,这个过程称为方法重写/方法覆盖

  • 代码满足什么条件会触发方法覆盖?

    • 发生在具有继承关系的父子类之间
    • 返回值类型相同,方法名相同,形参数列表相同
    • 访问权限不能更低,可以更高
    • 抛出异常不能更多,可以更少
  • 方法重新建议复制过去改【防止写错】

  • 注意:

    • 私有方法不能继承,所以不能覆盖
    • 构造方法不能继承,所以不能覆盖
    • 静态方法不存在覆盖【后面多态详讲】
    • 覆盖只针对方法,不谈属性
// 创建动物类
public class Animal {

    public void move() {
        System.out.println("动物在移动");
    }
}
// 创建猫类
public class Cat extends Animal{

    // 重新父类方法
    public void move() {
        System.out.println("猫在走猫步");
    }
}
// 创建鸟类
public class Bird extends Animal{

    // 重新父类方法
    public void move() {
        System.out.println("鸟在飞");
    }
}
public class OverrideTest01 {

    public static void main(String[] args) {

        // 创建动物对象
        Animal a = new Animal();
        a.move();

        // 创建猫对象
        Cat c = new Cat();
        c.move();

        // 创建鸟对象
        Bird b = new Bird();
        b.move();
    }
}

多态

Java中多态机制【基础规则】

多态作用:

降低程序的耦合度【解耦合】,提高程序的可拓展性【尽量使用】

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

  • 关于多态中涉及的概念:

    • 向上转型(upcasting)

      • 子类型 --> 父类型

        又被称为:自动类型转换

      • 通过运行一定不会出问题

    • 向下转型(downcasting)

      • 父类型 --> 子类型

        又被称为:强制类型转换【需要加强制类型转换符】

      • 通过运行可能出问题【著名异常:java.lang.ClassCastException】

    • 无论是向下转型(upcasting)还是向上转型(downcasting),两种类型之间必须要有继承关系。没有继承关系无法通过编译

    • 当调用的方法是子类型特有,在父类型当中没有。必须进行向下转型(downcasting)

    • 在向下转型(downcasting)中如何避免 ClassCastException 异常

      使用 instanceof 运算符

        (引用 instanceof 数据类型名)
      

      计算结果为 Boolean【布尔类型】

      • true:表示这个引用指向的对象是此数据类型
      • false:表示这个引用指向的对象不是此数据类型
    • Java规范中要求:在使用强制类型转换前,建议采用 instanceof 运算符判断,避免 ClassCastException 异常

Animal、Cat、Bird三个类之间的关系:

  • Cat 继承 Animal
  • Bird 继承 Animal
  • Cat 与 Bird无继承关系
// 创建动物类
public class Animal {

    public void move() {
        System.out.println("动物在移动");
    }
}
// 创建猫类
public class Cat extends Animal{

    // 重新父类方法
    public void move() {
        System.out.println("猫在走猫步");
    }

    // 不是从父类中继承的方法
    // 这个方法是子类对象特有行为
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}
// 创建鸟类
public class Bird extends Animal{

    // 重新父类方法
    public void move() {
        System.out.println("鸟在飞");
    }

    // 子类对象特有行为
    public void fly() {
        System.out.println("Bird fly !");
    }
}
public class Test {

    public static void main(String[] args) {

        // 以前编写的程序

        // 创建动物对象
        Animal a1 = new Animal();
        a1.move();

        // 创建猫对象
        Cat c1 = new Cat();
        c1.move();
        c1.catchMouse();

        // 创建鸟对象
        Bird b1 = new Bird();
        b1.move();

        // 使用动态机制
        System.out.println("-----以下使用动态机制----");

        Animal a2 = new Cat();  // 想象 long num = 10;
        // Cat is a Animal
        // new Cat()创建的对象类型是Cat,Animal a2中 a2 引用的数据类型是Animal,可见它们进行类型转换
        // 子类型转换父类型,称为向上转型(upcasting),或者自动类型转换

        // Bird b2 = new Cat();     Bird与Cat无继承关系


        // 编译器只会把a2类型视作Animal
        // 运行时是看底层的实际内容
        a2.move();  // 猫在走猫步

        // a2.catchMouse();     报错
        // 编译器检查为Animal类型,Animal中没有catchMouse()方法,导致静态绑定失败


        // 需求:需要a2去执行catchMouse()方法
        // 可以通过向下转型(downcasting),强制转换,同样需要两者有继承关系
        Cat c2 = (Cat)a2;
        c2.catchMouse();



        // 父类型引用指向子类型对象【多态】
        // 以下程序编译无错语法允许,但运行阶段报错JVM堆内存实际存在的是Bird对象
        // 类型之间不存在如何继承关系,会发生著名异常:java.lang.ClassCastException
        // 触发一般在向下转型(downcasting),一定注意

        // Animal  a3 = new Bird();
        // Cat c3 = (Cat)a3;

        // c3.catchMouse(); 报错    著名异常:java.lang.ClassCastException

        // 避免ClassCastException
        Animal  a3 = new Bird();

        if(a3 instanceof Cat) {
            Cat c3 = (Cat)a3;
            c3.catchMouse();
        }else if(a3 instanceof Bird){
            Bird b3 = (Bird)a3;
            b3.fly();
        }

    }
}

  1. java程序永远都分为编译阶段和运行阶段
  2. 先分析编译阶段,再分析运行阶段,编译无法通过,根本无法运行
  3. 编译阶段编译器检查a2这个引用的数据类型是Animal,由于Animal.class字节码当中有move()方法,所以编译通过,这个过程我们称为静态绑定,编译阶段绑定。只有静态绑定成功之后才有程序运行
  4. 在程序运行阶段,JVM堆内存中真实创建的对象是Cat对象,那么上述程序中 a2.move(); 一定调用Cat对象的move()方法【方法重写无关】,称为动态绑定,运行阶段绑定
  5. 无论重写与否,运行阶段只与底层实际关联

父类型引用指向子类型对象这种机制导致程序在编译阶段绑定和运行阶段绑定两种不同的形态,这种机制可以成为一种动态语法机制


Java面向对象



posted @ 2022-02-05 17:50  sha0dow  阅读(49)  评论(0编辑  收藏  举报