Java多态依赖运行时动态绑定,核心是根据对象实际类型调用重写后的方法,需同时满足继承/实现关系、子类重写非static/private/final方法、父类或接口类型引用指向子类实例三个条件。
多态靠动态绑定,不是编译时决定的
Java 多态的核心是「运行时根据对象实际类型调用方法」,而不是看变量声明的类型。比如
,编译器只检查
类里有没有
;真正执行时,JVM 查的是
这个对象的实际类型,然后去
的方法表里找重写后的实现。
静态方法、
方法、
方法不参与动态绑定——它们在编译期就绑定了,调用时只看引用的编译时类型
构造方法不能被重写,所以也不构成多态
接口实现和类继承效果一致:只要
且
实现了
,就触发动态绑定
必须同时满足三个条件,缺一不可
光写个
不等于有多态;光有继承也不行。真正生效要三者齐备:
存在继承或实现关系(
或
)
子类重写了父类/接口中的非静态、非私有、非 final 方法
使用父类/接口类型引用指向子类实例(即向上转型:
)
常见错误:写成
——这没用到父类引用,只是普通调用,不体现多态;或者子类没加
却以为重写了,结果调用的还是父类方法。
方法表(vtable)是 JVM 实现动态绑定的关键结构
JVM 为每个类维护一张方法表,表中按签名顺序存放可被动态调用的方法地址。子类加载时,会复制父类方法表,再把重写的方法替换成自己的入口地址。调用时,JVM 直接查这张表,跳转到对应实现。
立即学习
“
Java免费学习笔记(深入)
”;
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
这意味着:
多态调用性能几乎无损耗(现代 JVM 还做了内联优化)
如果子类没重写某个方法,方法表里仍指向父类实现,所以能正常回退
方法不在方法表里——它属于类,不依赖实例,所以
和
是两个独立符号,不构成多态
别混淆重载(Overload)和重写(Override)
重载是编译时多态,发生在同一个类里,靠参数列表区分;重写才是运行时多态,发生在父子类之间,靠实际对象类型区分。两者机制完全不同,混用会导致预期外的行为。
典型陷阱:
父类有
,子类加了个
——这是重载,不是重写,多态不会生效
子类方法返回类型写成
,父类是
,没问题(协变返回值);但如果写成
而父类是
,编译直接报错
子类把方法改成
,而父类是
,编译通过但运行时报
(访问权限收缩违反重写规则)
真正理解多态,关键不是记住“父类引用子类对象”这句话,而是盯住「运行时对象类型」和「方法是否可被动态绑定」这两个点。其他都是围绕它展开的约束和优化。
Animal a = new Dog()AnimalmakeSound()new Dog()DogprivatefinalShape s = new Circle()Circledraw()@OverrideextendsimplementsAnimal a = new Cat()Cat c = new Cat(); c.makeSound();@OverridestaticAnimal.staticMethod()Dog.staticMethod()void show(Object o)void show(String s)StringObjectIntegerStringprotectedpublicIllegalAccessError