继承、重写和多态

继承、重写和多态

还是最经典的例子,Animal, Cat, Dog

继承

关于继承,先总结,再给出代码示例

关于Java中的继承:

  • 1 继承继承是面向对象三大特征之一 (封装、 继承、 多态)
  • 2 继承的基本作用:代码复用,但是继承最重要的作用是有了继承才有了 “重写” 和 “多态机制”。
  • 3 继承语法格式:
     class 类名 extends 父类名 {
          属性 ;
          方法()
     } 
  • 4 java中只支持单继承,一个类不能同时继承多个类。
  • 5 一些基本术语:
     /**
      * A可以称为:父类、基类、超类、superclass 
      * B可以称为:子类、派生类、subclass  
      **/
     class A extends B {}        
  • 6 私有的不继承

      构造方法不继承

      其他数据均可继承
  • 7 虽然java不支持多继承,但可以间接继承,例如:
     /**
      * A直接继承B, A间接继承C, D
      **/
     class A extends B {}
     class B extends C {}
     class C extends D {}
  • 8 所有类默认继承java.lang.Object类

示例

public class Animal {
    public void move() {
        System.out.println("Animal is moving");
    }
}
public class Cat extends Animal {
    @override   // 重写
    public void move() {
        System.out.println("cat is moving");
    }
}
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.move();
    }
}

运行结果:

cat is moving

(若Cat类中没有重写,则结果为 Animal is moving)


重写

  • 当父类方法无法满足子类的业务需求时,子类有必要将父类中继承的方法进行重写。(例如上面的Animal和Cat)
  • 重写需要满足的条件:
      方法重写发生在具有继承关系的父子类之间
      返回值类型相同,方法名相同,形参列表相同
      访问权限不能更低,抛出异常不能更多
  • 私有方法不能继承,所以更不能重写
  • 构造方法不能继承,更不能重写
  • 静态方法不存在重写
  • 重写只针对方法,不谈属性



多态

public class Animal {
    public void move() {
        System.out.println("animal is moving");
    }
}
public class Cat extends Animal {

    // 重写父类方法
    @Override
    public void move() {
        System.out.println("cat is moving");
    }

    // 不是从父类继承的,子类特有方法
    public void catchMouse() {
        System.out.println("catch mouse");
    }
}
public class Dog extends Animal {
    @Override
    public void move() {
        System.out.println("dog is moving");
    }
}
/**
 * 关于多态:
 *   1 Animal,Cat,Dog之间的关系:
 *       Cat和Dog都继承自Animal
 *       Cat和Dog之间没有继承关系
 *   2 关于多态的几个概念:
 *       向上转型(自动类型转换): 子 --> 父
 *       向下转型(强制类型转换): 父 --> 子
 *       转型时,两者之间必须要有继承关系
 *       没有继承关系,无法编译通过
 */
public class Test {
    public static void main(String[] args) {

        Animal a = new Cat();

        /**
         * 1 编译阶段编译器检查"a"这个引用的数据类型为Animal,由于Animal.class字节码中有move()方法,
         *      所以编译通过。这个过程称为静态绑定,编译阶段绑定,只有静态绑定成功之后才有后续的运行。
         *
         * 2 程序运行阶段,JVM堆内存当中真实创建的对象是Cat对象,则程序在运行时会调用Cat的move()方法,
         *      此时发生了程序的动态绑定,运行阶段绑定。
         *
         * 3 注意:这里 a 调用的move()方法是 Cat 的move()方法,从父类继承而来,与是否重写无关
         */
        a.move();

        /**
         * a.catchMouse()无法通过编译,原因:
         * 1 Java程序分为编译阶段和运行阶段
         * 2 先分析编译阶段,再分析运行阶段。编译无法通过,程序无法运行
         * 3 编译阶段编译器检查"a"这个引用的数据类型为Animal,不存在catchMouse()方法,
         *      导致静态绑定失败,编译失败,更别谈运行了。
         */
        // a.catchMose();
    }
}

运行结果:

cat is moving


那么该如何调用catchMose()方法呢?



强制类型转换

  • 为了使用子类特有的方法,我们需要进行强制类型转换,同样是上面的Animal和Cat
    public class Test {
        public static void main(String[] args) {
            Animal a2 = new Cat();
            Cat c = (Cat) a2;
            c.catchMouse;
      }
    }
    

运行结果:

catch mouse


  • 补充一个非常经典的异常 :java.lang.ClassCastException
    public class Test {
        public static void main(String[] args) {
            Aniaml a3 = new Dog();
            Cat c1 = (Cat) a3;
        }
    }
    
  • 以上程序在编译时没有错误,因为编译阶段 a3 是一个Animal类型,可以强转为Cat
  • 但是运行时会报错,因为真实对象是Dog类型,与Cat之间不存在继承关系
  • 运行结果:
    在这里插入图片描述
  • 以上异常只会出现在向下转型时,向上转型只要编译通过就不会有问题

当然啦,这个异常我们也是有办法应对的,那就是 instanceof

  • instanceof返回的是一个boolean类型的值
    public class Test {
        public static void main(String[] args) {
            Animal a3 = new Dog();
            if (a3 instanceof Cat) {      // a3是否为Cat的实例
                Cat c = (Cat) a3;
                c.catchMouse();
            } else if (a3 instanceof Dog) {
                Dog d = (Dog) a3;
                d.move();
            }
        }
    }
    

运行结果:

dog is moving

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章