静态与动态绑定
- 静态绑定:编译时进行,编译器只看变量的引用类型
- 动态绑定:运行时进行,JVM根据对象在堆中的实际类型来调用方法
函数的重载overload是静态绑定。编译器根据传入参数的类型选择对应的函数
static方法是静态绑定,仅根据引用类型来调用方法,编译器在编译时就确定了调用哪个方法。
重写override是动态绑定,发生在运行时
final, private和static方法不能被重写,因此它们是静态绑定的。
多态
多态的实现分两步
- 编译时:编译器根据引用类型来选择方法
- 运行时:JVM根据对象在堆中的实际类型来调用方法
例如
public class Animal {
public String show(Animal obj) {
return "Animal : Animal";
}
public String show(Dog obj) {
return "Animal : Dog";
}
}
public class Dog extends Animal{
@Override
public String show(Animal obj) {
return "Dog : Animal";
}
public String show(Puppy obj) { // Puppy 是 Dog 的子类,假设已定义
return "Dog : Puppy";
}
}
public class Puppy extends Dog{
}
public class Main {
public static void main(String[] args) {
Animal aRefDog = new Dog();
Puppy p = new Puppy();
System.out.println(aRefDog.show(p));
}
}执行System.out.println(aRefDog.show(p));发生如下几步
- 编译时,
aRefDog的引用类型是Animal,编译器在Animal类中查找show方法 - 编译器由参数
p类型是Puppy,没有对应的方法,就选择最接近的show(Dog obj)方法 - 运行时,
aRefDog的实际类型是Dog,JVM在Dog类中查找show(Dog obj)方法是否被重写 - 没有重写,所以调用
Animal类的show(Dog obj)方法,输出结果为Animal : Dog
类型转换
- 向上转型:子类引用转换为父类引用,可以直接赋值,无需强制转换
- 向下转型:父类引用转换为子类引用,需要强制转换。被转换的父类引用必须指向一个子类对象或者子类的子类对象,否则会抛出
ClassCastException异常
逻辑如下:必须保证引用类型对应的类所有方法都可以通过这个引用被调用
例如:
Animal aRefDog = new Dog();
Dog d = (Dog) aRefDog;
必须保证d对应的Dog类的所有方法都可以通过d被调用
- 编译时只看类型,子类引用可以直接转为父类引用,父类引用必须强制变成子类引用
- 运行时,子类引用转父类引用无需检查,因为子类一定有父类的方法,不会报错。
- 运行时,父类引用转子类引用需要检查,因为父类不一定有子类方法