多态初识
调用成员的特点
成员变量:编译看左边,运行看左边
成员方法:编译看左边,运行看右边
多态在调用成员变量时为什么是父类的,但是方法是子类的?
🧠 一句话解释:
在编译时(静态绑定),成员变量是根据引用类型(也就是声明的类型)来决定的;
在运行时(动态绑定),方法是根据对象的实际类型(也就是 new 出来的类型)来决定的。
👇 举个经典例子
class Parent {
public String name = "Parent";
public void sayHi() {
System.out.println("Hi from Parent");
}
}
class Child extends Parent {
public String name = "Child";
@Override
public void sayHi() {
System.out.println("Hi from Child");
}
}
public class Test {
public static void main(String[] args) {
Parent obj = new Child();
System.out.println(obj.name); // 输出:Parent
obj.sayHi(); // 输出:Hi from Child
}
}
🔍 为什么变量是父类的?
Java 对成员变量的访问是静态绑定的。也就是说:
- 编译器在编译阶段就决定了访问的是哪个变量。
- 因为
obj
是Parent
类型的引用,所以直接去找Parent.name
,不管你指向的是Child
对象。
✅ 所以访问的是
Parent
中的name
,输出Parent
。
🔍 为什么方法是子类的?
Java 中的方法调用(如果是 非 static
的实例方法)是动态绑定的,也就是说:
- 编译时只检查你有没有这个方法。
- 运行时会看真实的对象是谁,再调用那个类中“最合适的版本”。
✅ 所以
obj.sayHi()
实际运行的是Child
中的重写方法,输出Hi from Child
。
✅ 总结记忆法
成员 | 绑定方式 | 决定于 | 行为 |
---|---|---|---|
变量 | 静态绑定 | 引用类型 | 看“左边” |
方法 | 动态绑定 | 实际对象 | 看“右边” |
多态优势
- 方法中,使用父类型作为参数,可以接收所有子类对象
多态弊端
- 不能调用子类的特有功能