继承、重写和多态
还是最经典的例子,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