1. 程式人生 > >Java 橋接方法(Bridge Method)

Java 橋接方法(Bridge Method)


什麼是「橋接方法」,下面來從兩個例子中體會一下。

重寫方法的返回型別是其父類返回型別的子型別

public class Merchant {
    public Number actionPrice(double price) {
        return price * 0.8;
    }
}

public class NaiveMerchant extends Merchant {

    @Override
    public Double actionPrice(double price) {
        return 0.9 * price;
    }

    public
static void main(String[] args) { Merchant merchant = new NaiveMerchant(); // price 必須定義成 Number 型別 Number price = merchant.actionPrice(40); System.out.println(price); } }
 javac  Merchant.java NaiveMerchant.java
 # 反編譯位元組碼 
 javap -v -c NaiveMerchant

檢視 NaiveMerchant.class 反編譯後位元組碼:

 public java.lang.Double actionPrice(double);
    descriptor: (D)Ljava/lang/Double;
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=3, args_size=2
         0: dload_1
         1: ldc2_w        #2                  // double 0.9d
         4: dmul
         5: invokestatic  #4                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
         8: areturn
      LineNumberTable:
        line 13: 0

// 橋接方法         
public java.lang.Number actionPrice(double);
    descriptor: (D)Ljava/lang/Number;
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=3, locals=3, args_size=2
         0: aload_0
         1: dload_1
         2: invokevirtual #12                 // Method actionPrice:(D)Ljava/lang/Double;
         5: areturn
      LineNumberTable:
        line 9: 0

父類 Merchant 的 actionPrice 的返回值是 Number 型別,子類NaiveMerchant 重寫 actionPrice 返回的值類似是 Double 型別,對於 Java 語言是重寫的,但對於 Java 虛擬機器解析來說卻不是重寫的,只有當兩個方法的引數型別以及返回型別一致時,Java 虛擬機器才會判定為重寫,為了保持重寫的語義,Java 編譯器會在 NaiveMerchant 的位元組碼檔案中自動生成一個橋接方法來保證重寫語義:

flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
ACC_BRIDGE:表示這個一個橋接方法
ACC_SYNTHETIC:表示這個方法由編譯器自動生成
public java.lang.Number actionPrice(double);

翻譯橋接方法的位元組碼:

public Number actionPrice(double price) {
     return this.actionPrice(price);
}

這個橋接方法會去呼叫 NaiveMerchant 本身重寫的方法。

編譯器通過插入橋接方法來保證重寫的語義,從而 Java 虛擬機器通過方法描述符(由方法的引數型別和返回型別構成)定位到具體方法,執行方法呼叫:

   Merchant merchant = new NaiveMerchant();
   // 這裡實際上呼叫的則是橋接方法 
   Number price = merchant.actionPrice(40);

重寫泛型方法生成橋接

子類在繼承父類的一個泛型方法、或子類實現一個介面的泛型方法,編譯器會在子類的 class 檔案中自動生成橋接方法。

interface Customer {
    String purchase();
}

class VIP implements Customer {
    @Override
    public String purchase() {
        return "VIP First !";
    }
}

class NOT_VIP implements Customer {
    @Override
    public String purchase() {
        return "VIP First !";
    }
}

abstract class MerchantOther<T extends Customer> {
    public double actionPrice(double price, T customer) {
        return price * 0.08;
    }
}

class VIPOnlyMerchant extends MerchantOther<VIP> {
    @Override
    public double actionPrice(double price, VIP customer) {
        return price * 0.07;
    }
}

public class MethodFind {
    public static void main(String[] args) {
        
    }
}

反編譯父類 MerchantOther 的位元組碼檔案:
在這裡插入圖片描述
泛型 T 被換成了 Customer,方法簽名是:

public double actionPrice(double price, Customer customer);

再看 VIPOnlyMerchant.class 的位元組碼:
在這裡插入圖片描述
子類的位元組碼中有一個編譯器自動生成的橋接方法,這個橋接方法翻譯成 Java 程式碼就是:

public double actionPrice(double price, Customer customer) {
    return this.actionPrice(price, (VIP) customer);
}

橋接方法呼叫了子類重寫的泛型方法,執行下面的程式碼:

  public static void main(String[] args) {
        MerchantOther merchantOther = new VIPOnlyMerchant();
        // 呼叫實際的方法
        merchantOther.actionPrice(80, new VIP());
        // 呼叫的是橋接方法,出現 java.lang.ClassCastException 的異常
        merchantOther.actionPrice(90, new NOT_VIP());
    }

由於泛型擦除,父類 MerchantOther 的引數實際上是 Customer 型別,為了保證重寫的語義,相容 1.5(泛型是在 1.5 引入的) 之前的位元組碼檔案,所以生成橋接方法。new NOT_VIP() 傳入 Customer 型別的引數,編譯器也不會發現錯誤。執行時呼叫了橋接方法,橋接方法中使用 VIP 進行強制型別轉換,當引數型別不是 VIP 時,就會丟擲型別轉換異常。

相關推薦

Java 方法Bridge Method

什麼是「橋接方法」,下面來從兩個例子中體會一下。 重寫方法的返回型別是其父類返回型別的子型別 public class Merchant { public Number actionPrice(double price) { retur

泛型擦除type erasure方法bridge method

無界萬用字元會被編譯為Object,有邊界的萬用字元會被編譯為相應的邊界   正常類的繼承是不會產生這個橋接方法的。 橋接方法,一個類、介面繼承或實現某個類、介面時,會在子類中出現一個橋接方法。 這個方法不能被子類呼叫,即mn不能呼叫到這個橋接方法,但是n可以呼

重走Java設計模式——模式Bridge Pattern

橋接模式 定義 將抽象部分與實現部分分離,使它們都可以獨立的變化。 結構詳解 橋接模式主要包含如下幾個角色: 1.Abstraction:抽象類; 2.RefinedAbstraction:擴充抽象類; 3.Implementor:實現類介面; 4.Co

Java模式Bridge-結構型

意圖 將抽象化與實現化解耦,使二者可以獨立地變化。 類圖與角色 抽象化角色(Abstraction):定義抽象化的介面。並儲存一個對Implementor物件的引用。 修正抽象化角色(Refined Abstraction):改變和修正Abstraction對抽象化的定義

設計模式之模式Bridge Pattern

設計模式之橋接模式(Bridge Pattern) 備註:只是瞭解了大概,在實際應用中還沒有 1.用處 將抽象部分與實現部分分離,使它們都可以獨立的變化。 2. 分類 結構型模式 3. UML 4. 程式碼 測試類Test public class Test { publ

模式Bridge Pattern——處理多維度變化

前言 P: 嘿,小重樓!我們這邊有個簡單的需求,交個你了。 me: 啥需求?我拒絕!!! P: 呀?你小子敢拒絕老孃的需求,活膩了吧? me: 好吧,我接。。。做啥呢?我接。。。 P: 我這邊需要開發一個視訊播放器。不僅要跨平臺(Linux,Mac,W

C#設計模式-模式Bridge Pattern

引言 例如我有好幾個專案,需要外包出去做各種型別的測試,不同的公司基礎費用不同,不同的測試型別價格也是不同的。此時不同的專案選擇不同的公司和不同型別的測試進行測試價格都是不同的。於是我們可以建立一個專案抽象類,一個公司抽象類,一個測試型別抽象類,然後實現各自的具體類,不同的專案使用不同的公司和測試型別,進行測

JAVA設計模式07:結構型-模式Bridge

     在正式介紹橋接模式之前,我先跟大家談談兩種常見文具的區別,它們是毛筆和蠟筆。假如我們需要大中小3種型號的畫筆,能夠繪製12種不同的顏色,如果使用蠟筆,需要準備3×12 = 36支,但如果使用毛筆的話,只需要提供3種型號的毛筆,外加12個顏料盒即可,涉及到的物

【Linux Is Not Unix】虛擬機器下CentOS配置ip三種方法1-模式bridge

  在bridged模式下,VMWare虛擬出來的作業系統就像是區域網中的一臺獨立的主機,它可以訪問網內任何一臺機器。在bridged模式下,你需要手工為虛擬系統配置IP地址、子網掩碼,而且還要和宿

設計模式之十八:模式Bridge

ora 它的 pla sin string src ams down ng- 橋接模式: 將抽象部分和它的實現部分相分離開來,以使它們能夠單獨地變化。 UML圖: 主要包含: Abstraction:定義了抽象部分的接口。操作一個實現部分對

C#設計模式之八模式Bridge【結構型】

升級 方向 implement 詳細 .cn mage names 這樣的 意圖 一、引言 今天我們要講【結構型】設計模式的第二個模式,該模式是【橋接模式】,也有叫【橋模式】的。大家第一次看到這個名稱會想到什麽呢?我第一次看到這個模式根據名稱猜肯定是連接什麽東西的。因為

C#設計模式系列:模式Bridge

span -i 原來 派生 引用 分享圖片 on() 版本 nta 1.1定義 當一個抽象可能有多個實現時,通常用繼承來進行協調。抽象類定義對該抽象的接口,而具體的子類則用不同的方式加以實現。繼承機制將抽象部分與它的實現部分固定在一起,使得難以對抽象部分和實現部分獨立地進行

設計模式-模式Bridge

橋接模式是構造型模式之一。把抽象(Abstraction)與行為實現(Implementor)分離開來,從而可以保持各部分的獨立性以及應對它們的功能擴充套件。 角色和職責: 1.抽象類(Abstraction)-Car:    維護對行為實現(Implementor)的引用 2.具

java設計模式】之 模板方法Template Method模式

1. 模板方法的一個例項         這一節主要來學習一下設計模式中的模板方法模式。我們先來看一個例子:假如現在老闆讓你做一個汽車的模型,要求只要完成基本功能即可,不考慮擴充套件性,那你會怎麼做呢?我們首先會根據經驗設計一個類圖:        由這個類圖可知,非

設計模式-結構型- 模式Bridge

定義 將抽象部分與它的實現部分分享,使它們都可以獨立地變化 角色 抽象角色(Abstraction):定義了抽象類的介面而且維護著一個指向實現角色的引用 具體抽象角色(RefinedAbstr

設計模式 | 模式bridge

定義: 將抽象部分與它的實現部分分離,使它們都可以獨立地變化 結構:(書中圖,侵刪)   一個抽象類,用於聚合實現 若干個實現抽象類的類 一個實現的父類 若干個實現了父類的具體實現類 例項: 我想到了一個工作中的例子,通常我們需要去對接一些第三方平臺。 假如最開始你需要對接淘寶平臺,去建立銷售單。

設計模式的征途—17.模板方法Template Method模式

opened res ati 相同 rom 配置 version factor creat 在現實生活中,很多事情都需要經過幾個步驟才能完成,例如請客吃飯,無論吃什麽,一般都包含:點單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點單=>吃東西=>買單

Pandas學習筆記,字符串方法string method

api long top method hand capi borde tle row 一般語法格式Series.str.method()。具體方法見http://pandas.pydata.org/pandas-docs/stable/api.html#string-ha

設計模式-工廠方法Factory Method

log face inf str ace 對象實例 method tee 就是 2018-1-20 by Atlas 應用場景 Template Method Pattern是在父類建立處理邏輯的大綱骨架,而在子類補充具體的處理內容。把Template Method

設計模式2——建立型——工廠相關:簡單工廠Simple factory,工廠方法Factory method,抽象工廠Abstract factory

概要 這裡試圖描述23個設計模式中的兩個工廠(Factory)相關的設計模式:工廠方法(Factorymethod),抽象工廠(Abstract factory)。 注意點: 這兩個都屬於建立型設計模式。 由於這兩個設計模式都