Java多態(tài)概念、實(shí)現(xiàn)機(jī)制與實(shí)踐應(yīng)用詳解
前言
多態(tài)(Polymorphism)是 Java 面向?qū)ο缶幊讨械暮诵奶匦灾唬c封裝、繼承共同構(gòu)成了面向?qū)ο笤O(shè)計(jì)的基礎(chǔ)。理解多態(tài)不僅有助于寫出更加靈活、可擴(kuò)展的代碼,也能幫助我們更好地理解 Java 框架(如 Spring)背后的設(shè)計(jì)思想。
一、什么是 Java 的多態(tài)
在 Java 中,多態(tài)指的是:
同一個(gè)父類(或接口)引用,在不同子類對(duì)象上調(diào)用同一個(gè)方法時(shí),表現(xiàn)出不同的行為。
換句話說(shuō),方法的調(diào)用結(jié)果并不是由“引用的類型”決定,而是由“對(duì)象的實(shí)際類型”決定。
一個(gè)簡(jiǎn)單示例如下:
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)行時(shí)會(huì)根據(jù)對(duì)象的真實(shí)類型調(diào)用不同的實(shí)現(xiàn),這就是多態(tài)。
二、多態(tài)成立的基本條件
Java 中的運(yùn)行時(shí)多態(tài)通常需要滿足以下條件:
- 存在繼承關(guān)系或接口實(shí)現(xiàn)關(guān)系
- 子類對(duì)父類方法進(jìn)行了重寫
- 使用父類或接口類型的引用指向子類對(duì)象
其中第三點(diǎn)通常也被稱為“向上轉(zhuǎn)型”。
Animal animal = new Dog();
這種寫法是多態(tài)得以發(fā)揮作用的前提。
三、方法重寫與多態(tài)的關(guān)系
多態(tài)依賴于方法重寫(Override),而不是方法重載(Overload)。
方法重寫要求:
- 方法名相同
- 參數(shù)列表相同
- 返回值類型兼容
- 訪問(wèn)權(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)通過(guò)父類引用調(diào)用 test() 方法時(shí),真正執(zhí)行的是子類中的實(shí)現(xiàn)。
四、方法重載不是多態(tài)
雖然方法重載和多態(tài)在名字上容易混淆,但二者本質(zhì)完全不同。
class Demo {
void test(int a) {}
void test(String s) {}
}
方法重載是在編譯期根據(jù)參數(shù)類型決定調(diào)用哪個(gè)方法,不涉及運(yùn)行時(shí)的動(dòng)態(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
原因是:
成員變量的訪問(wèn)只與引用類型有關(guān),與對(duì)象的實(shí)際類型無(wú)關(guān)。
常見(jiàn)總結(jié)為一句話:
變量看左邊,方法看右邊。
六、static、final、private 方法與多態(tài)
并不是所有方法都參與多態(tài)。
static 方法
static 方法屬于類,而不是對(duì)象,在編譯期就已經(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 方法對(duì)子類不可見(jiàn),無(wú)法被重寫,也不存在多態(tài)行為。
七、接口與抽象類中的多態(tài)
接口多態(tài)
接口是 Java 中最常見(jiàn)、也是最重要的多態(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();
通過(guò)接口類型引用不同實(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)行時(shí)多態(tài)在 JVM 層面主要依賴 虛方法表(Virtual Method Table,vtable)。
其核心機(jī)制是:
- 每個(gè)類在加載時(shí)都會(huì)生成一張?zhí)摲椒ū?/li>
- 表中存放的是可被重寫的方法入口
- 方法調(diào)用時(shí),根據(jù)對(duì)象的實(shí)際類型查找虛方法表
- JVM 使用
invokevirtual指令完成動(dòng)態(tài)分派
以下方法不會(huì)進(jìn)入虛方法表:
- static 方法
- final 方法
- private 方法
- 構(gòu)造方法
九、多態(tài)在實(shí)際開(kāi)發(fā)中的價(jià)值
多態(tài)的最大價(jià)值體現(xiàn)在以下幾個(gè)方面:
- 降低模塊之間的耦合
- 提高系統(tǒng)的可擴(kuò)展性
- 支持面向接口編程
- 符合開(kāi)閉原則(對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉)
例如:
List list = new ArrayList(); list = new LinkedList();
調(diào)用方代碼無(wú)需修改,只需替換實(shí)現(xiàn)即可獲得不同的行為。
十、總結(jié)
多態(tài)是 Java 面向?qū)ο笤O(shè)計(jì)中的核心機(jī)制,其本質(zhì)是運(yùn)行期動(dòng)態(tài)綁定。
方法的實(shí)際執(zhí)行由對(duì)象的真實(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從基礎(chǔ)到實(shí)戰(zhàn)詳解SpringBoot獲取資源文件全指南
在 SpringBoot 開(kāi)發(fā)中,我們經(jīng)常需要訪問(wèn)各類資源文件,本文將系統(tǒng)講解 SpringBoot 中資源文件的存放規(guī)則,獲取方法及實(shí)戰(zhàn)技巧,需要的可以了解下2025-07-07
在spring?boot3中使用native?image的最新方法
這篇文章主要介紹了在spring?boot3中使用native?image?,今天我們用具體的例子來(lái)給大家演示一下如何正確的將spring boot3的應(yīng)用編譯成為native image,需要的朋友可以參考下2023-01-01
mybatis?resultMap之collection聚集兩種實(shí)現(xiàn)方式
本文主要介紹了mybatis?resultMap之collection聚集兩種實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09
IntelliJ IDEA中SpringBoot項(xiàng)目通過(guò)devtools實(shí)現(xiàn)熱部署的方法
這篇文章主要介紹了IntelliJ IDEA中SpringBoot項(xiàng)目通過(guò)devtools實(shí)現(xiàn)熱部署的方法,本文分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08

