Java多態(tài)概念、實(shí)現(xiàn)機(jī)制與實(shí)踐應(yīng)用詳解
前言
多態(tài)(Polymorphism)是 Java 面向?qū)ο缶幊讨械暮诵奶匦灾?,與封裝、繼承共同構(gòu)成了面向?qū)ο笤O(shè)計(jì)的基礎(chǔ)。理解多態(tài)不僅有助于寫出更加靈活、可擴(kuò)展的代碼,也能幫助我們更好地理解 Java 框架(如 Spring)背后的設(shè)計(jì)思想。
一、什么是 Java 的多態(tài)
在 Java 中,多態(tài)指的是:
同一個父類(或接口)引用,在不同子類對象上調(diào)用同一個方法時,表現(xiàn)出不同的行為。
換句話說,方法的調(diào)用結(jié)果并不是由“引用的類型”決定,而是由“對象的實(shí)際類型”決定。
一個簡單示例如下:
class Animal {
public void sound() {
System.out.println("animal");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("wang");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("miao");
}
}
public class Demo {
public static void main(String[] args) {
Animal a1 = new Dog();
Animal a2 = new Cat();
a1.sound();
a2.sound();
}
}
運(yùn)行結(jié)果
wang miao
變量看左邊,方法看右邊。
雖然變量類型都是 Animal,但在運(yùn)行時會根據(jù)對象的真實(shí)類型調(diào)用不同的實(shí)現(xiàn),這就是多態(tài)。
二、多態(tài)成立的基本條件
Java 中的運(yùn)行時多態(tài)通常需要滿足以下條件:
- 存在繼承關(guān)系或接口實(shí)現(xiàn)關(guān)系
- 子類對父類方法進(jìn)行了重寫
- 使用父類或接口類型的引用指向子類對象
其中第三點(diǎn)通常也被稱為“向上轉(zhuǎn)型”。
Animal animal = new Dog();
這種寫法是多態(tài)得以發(fā)揮作用的前提。
三、方法重寫與多態(tài)的關(guān)系
多態(tài)依賴于方法重寫(Override),而不是方法重載(Overload)。
方法重寫要求:
- 方法名相同
- 參數(shù)列表相同
- 返回值類型兼容
- 訪問權(quán)限不能變小
示例:
class Parent {
public void test() {
System.out.println("parent");
}
}
class Child extends Parent {
@Override
public void test() {
System.out.println("child");
}
}
當(dāng)通過父類引用調(diào)用 test() 方法時,真正執(zhí)行的是子類中的實(shí)現(xiàn)。
四、方法重載不是多態(tài)
雖然方法重載和多態(tài)在名字上容易混淆,但二者本質(zhì)完全不同。
class Demo {
void test(int a) {}
void test(String s) {}
}
方法重載是在編譯期根據(jù)參數(shù)類型決定調(diào)用哪個方法,不涉及運(yùn)行時的動態(tài)綁定,因此不屬于多態(tài)。
五、成員變量是否具有多態(tài)性
成員變量不具備多態(tài)性。
class A {
int x = 10;
}
class B extends A {
int x = 20;
}
A a = new B();
System.out.println(a.x);
輸出結(jié)果為:
10
原因是:
成員變量的訪問只與引用類型有關(guān),與對象的實(shí)際類型無關(guān)。
常見總結(jié)為一句話:
變量看左邊,方法看右邊。
六、static、final、private 方法與多態(tài)
并不是所有方法都參與多態(tài)。
static 方法
static 方法屬于類,而不是對象,在編譯期就已經(jīng)確定調(diào)用關(guān)系,因此不存在多態(tài)。
class A {
static void test() {
System.out.println("A");
}
}
class B extends A {
static void test() {
System.out.println("B");
}
}
A a = new B();
a.test(); // 輸出 A
final 方法
final 方法不能被重寫,因此也不具備多態(tài)。
private 方法
private 方法對子類不可見,無法被重寫,也不存在多態(tài)行為。
七、接口與抽象類中的多態(tài)
接口多態(tài)
接口是 Java 中最常見、也是最重要的多態(tài)使用形式之一。
interface Payment {
void pay();
}
class Alipay implements Payment {
public void pay() {
System.out.println("alipay");
}
}
class WechatPay implements Payment {
public void pay() {
System.out.println("wechat");
}
}
Payment payment = new Alipay();
payment.pay();
通過接口類型引用不同實(shí)現(xiàn)類,可以在不修改調(diào)用方代碼的情況下切換實(shí)現(xiàn)。
抽象類多態(tài)
抽象類同樣可以作為多態(tài)的基礎(chǔ)。
abstract class Shape {
abstract double area();
}
class Circle extends Shape {
double r;
Circle(double r) {
this.r = r;
}
double area() {
return Math.PI * r * r;
}
}
八、JVM 層面:多態(tài)是如何實(shí)現(xiàn)的
Java 的運(yùn)行時多態(tài)在 JVM 層面主要依賴 虛方法表(Virtual Method Table,vtable)。
其核心機(jī)制是:
- 每個類在加載時都會生成一張?zhí)摲椒ū?/li>
- 表中存放的是可被重寫的方法入口
- 方法調(diào)用時,根據(jù)對象的實(shí)際類型查找虛方法表
- JVM 使用
invokevirtual指令完成動態(tài)分派
以下方法不會進(jìn)入虛方法表:
- static 方法
- final 方法
- private 方法
- 構(gòu)造方法
九、多態(tài)在實(shí)際開發(fā)中的價值
多態(tài)的最大價值體現(xiàn)在以下幾個方面:
- 降低模塊之間的耦合
- 提高系統(tǒng)的可擴(kuò)展性
- 支持面向接口編程
- 符合開閉原則(對擴(kuò)展開放,對修改關(guān)閉)
例如:
List list = new ArrayList(); list = new LinkedList();
調(diào)用方代碼無需修改,只需替換實(shí)現(xiàn)即可獲得不同的行為。
十、總結(jié)
多態(tài)是 Java 面向?qū)ο笤O(shè)計(jì)中的核心機(jī)制,其本質(zhì)是運(yùn)行期動態(tài)綁定。
方法的實(shí)際執(zhí)行由對象的真實(shí)類型決定,而不是引用類型。
并非所有方法都具備多態(tài)特性,static、final、private 方法不參與多態(tài)。
接口和抽象類是實(shí)現(xiàn)多態(tài)的主要手段,多態(tài)也是現(xiàn)代 Java 框架設(shè)計(jì)的重要基礎(chǔ)。
到此這篇關(guān)于Java多態(tài)概念、實(shí)現(xiàn)機(jī)制與實(shí)踐應(yīng)用的文章就介紹到這了,更多相關(guān)Java多態(tài)實(shí)現(xiàn)機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn)
本文主要介紹了MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn),主要包括單個參數(shù)傳遞綁定,序號參數(shù)傳遞綁定,注解參數(shù)傳遞綁定,pojo(對象)參數(shù)傳遞綁定,map參數(shù)傳遞綁定這幾種類型,具有一定的參考價值,感興趣的可以了解一下2023-12-12
java實(shí)現(xiàn)動態(tài)時鐘并設(shè)置鬧鐘功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)動態(tài)時鐘并設(shè)置鬧鐘功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01
解讀Spring配置與服務(wù)組件的關(guān)系和注入機(jī)制
這篇文章主要介紹了解讀Spring配置與服務(wù)組件的關(guān)系和注入機(jī)制,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-09-09
spring boot使用RabbitMQ實(shí)現(xiàn)topic 主題
本篇文章主要介紹了spring boot使用RabbitMQ實(shí)現(xiàn)topic 主題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03
Java使用正則表達(dá)式(regex)匹配中文實(shí)例代碼
本文給大家分享java使用正則表達(dá)式匹配中文的實(shí)例代碼,以及java中要匹配中文的正則表達(dá)式兩種寫法,感興趣的朋友通過本文一起看看吧2016-12-12
JavaSwing基礎(chǔ)之Layout布局相關(guān)知識詳解
上次我們說到View的Mearsure流程,今天接著說說layout. 關(guān)于layout,很多朋友知道它是負(fù)責(zé)布局的,那么具體是怎么布局的?viewGroup和view的layout方法又有什么不同?一起來看看吧,需要的朋友可以參考下2021-05-05
Java8新特性lambda表達(dá)式有什么用(用法實(shí)例)
這篇文章主要介紹了Java8新特性lambda表達(dá)式有什么用,著重以實(shí)例講解lambda表達(dá)式,需要的朋友可以參考下2014-06-06
springboot中的靜態(tài)資源加載順序優(yōu)先級
這篇文章主要介紹了springboot中的靜態(tài)資源加載順序優(yōu)先級,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

