最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java編程 多態(tài)

 更新時間:2021年10月07日 09:06:10   作者:pursuingdreams  
這篇文章主要介紹了關于Java編程的多態(tài),多態(tài)通過分離做什么和怎么做,從另一個角度將接口和實現(xiàn)分離開來。構(gòu)建可擴展的程序,需要的朋友可以參考下

前言:

封裝,是合并屬性和行為創(chuàng)建一種新的數(shù)據(jù)類型,繼承是建立數(shù)據(jù)類型之間的某種關系(is-a),而多態(tài)就是這種關系在實際場景的運用。

多態(tài)就是把做什么和怎么做分開了;其中,做什么是指調(diào)用的哪個方法[play 樂器],怎么做是指實現(xiàn)方案[使用A樂器 使用B樂器],''分開了''指兩件事不在同一時間確定。

一、向上轉(zhuǎn)型

對象既可以作為它本身的類型使用,也可以作為它的基類型使用,而這種把對某個對象的引用視為對其基類型的引用的做法就是向上轉(zhuǎn)型。

example:

public enum Note {
 // 演奏樂符
    MIDDLE_C, C_SHARP, B_FLAT;

}
public class Instrument {

 // 樂器基類
    public void play(Note n) {
        print("Instrument.play()");
    }

}
public class Wind extends Instrument{

 // Wind是一個具體的樂器
    // Redefine interface method:
    public void play(Note n) {
        System.out.println("Wind.play() " + n);
    }

}
public class Music {

 // 樂器進行演奏
    public static void tune(Instrument i) {
        i.play(Note.MIDDLE_C);
    }

    public static void main(String[] args) {
        Wind flute = new Wind();
        tune(flute); // 向上轉(zhuǎn)型
    }
}

好處:

在上面例子中,如果讓tune方法接受一個Wind引用作為自己的參數(shù),似乎看起來更為直觀,但是會引發(fā)一個問題:這個時候你就需要為系統(tǒng)中Instrument的每種類型都編寫一個新的tune方法。所以我們只寫一個簡單的方法,僅僅接收基類作為參數(shù),而不是特殊的導出類,這么做情況不是變得更好嗎。

example:

class Stringed extends Instrument {
    public void play(Note n) {
        print("Stringed.play() " + n);
    }
}


class Brass extends Instrument {
    public void play(Note n) {
        print("Brass.play() " + n);
    }
}


public class Music2 {
    public static void tune(Wind i) {
        i.play(Note.MIDDLE_C);
    }

    public static void tune(Stringed i) {
        i.play(Note.MIDDLE_C);
    }


    public static void tune(Brass i) {
        i.play(Note.MIDDLE_C);

    }
    public static void main(String[] args) {
        Wind flute = new Wind();
        Stringed violin = new Stringed();
        Brass frenchHorn = new Brass();
        tune(flute); // No upcasting
        tune(violin);
        tune(frenchHorn);
    }
}

二、轉(zhuǎn)機

public static void tune(Instrument i) {
    // ...
    i.play(Note.MIDDLE_C);

}

在上面這個方法中,它接收一個Instrument引用,那么在這種情況下,編譯器怎么樣才能知道這個instrument引用指向的是Wind對象呢? ——通過后期綁定

1、綁定

將一個方法調(diào)用同一個方法主體關聯(lián)起來稱為綁定。

在程序執(zhí)行前進行綁定,就是前期綁定,比如C語言就只有一種方法調(diào)用,就是前期綁定。

在運行時根據(jù)對象的類型進行綁定就是后期綁定,也叫做動態(tài)綁定或者運行時綁定。

Java中除了static方法和final方法之外,其它所有方法都是后期綁定,這意味著通常情況下,我們不必判定是否應該進行后期綁定——它會自動發(fā)生。

2、擴展性

由于有多態(tài)機制,所以可根據(jù)自己的需要向系統(tǒng)里加入任意多的新類型,同時毋需更改 true()方法。在一個設計良好的 OOP 程序中,我們的大多數(shù)或者所有方法都會遵從 tune()的模型,而且只與基礎類接口通信。我們說這樣的程序具有“擴展性”,因為可以從通用的基礎類繼承新的數(shù)據(jù)類型,從而新添一些功能。如果是為了適應新類的要求,那么對基礎類接口進行操縱的方法根本不需要改變,
對于樂器例子,假設我們在基礎類里加入更多的方法[what/adjust],以及一系列新類[Woodwind/Brass],

例子:

class Instrument {
    void play(Note n) { print("Instrument.play() " + n); }
    String what() { return "Instrument"; }
    void adjust() { print("Adjusting Instrument"); }
}


class Wind extends Instrument {
    void play(Note n) { print("Wind.play() " + n); }
    String what() { return "Wind"; }
    void adjust() { print("Adjusting Wind"); }
}


class Percussion extends Instrument {
    void play(Note n) { print("Percussion.play() " + n); }
    String what() { return "Percussion"; }
    void adjust() { print("Adjusting Percussion"); }
}

class Stringed extends Instrument {
    void play(Note n) { print("Stringed.play() " + n); }
    String what() { return "Stringed"; }
    void adjust() { print("Adjusting Stringed"); }
}


class Brass extends Wind {
    void play(Note n) { print("Brass.play() " + n); }
    void adjust() { print("Adjusting Brass"); }
}


class Woodwind extends Wind {
    void play(Note n) { print("Woodwind.play() " + n); }
    String what() { return "Woodwind"; }
}


public class Music3 {
    // Doesn't care about type, so new types
    // added to the system still work right:
    public static void tune(Instrument i) {
        // ...
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] e) {
        for(Instrument i : e)
            tune(i);
    }
    public static void main(String[] args) {
        // Upcasting during addition to the array:
        Instrument[] orchestra = {
            new Wind(),
            new Percussion(),
            new Stringed(),
            new Brass(),
            new Woodwind()
        };
        tuneAll(orchestra);
    }
}

​ 為樂器系統(tǒng)添加更多的類型,而不用改動tune方法。tune方法完全可以忽略它周圍代碼所發(fā)生的全部變化,依舊正常運行。

3、缺陷

私有方法

private方法被自動修飾為final,而且對導出類是屏蔽的,所以在子類Derived類中的f方法是一個全新的方法。既然基類中的f方法在在子類Derived中不可見,那么也不能被重載。

域與靜態(tài)方法

任何域(field)的訪問操作都是由編譯器解析的,因此不是多態(tài)的。

如果某個方法是靜態(tài)的,那么它就不具有多態(tài)性

三、構(gòu)造器與多態(tài)

通常,構(gòu)造器不同于其它方法,涉及到多態(tài)時也是如此。構(gòu)造器是不具有多態(tài)性的

1、構(gòu)造器的調(diào)用順序

基類的構(gòu)造器總是在導出類的構(gòu)造過程中被調(diào)用,而且按照繼承層次逐漸向上鏈接。使得每個基類的構(gòu)造器都能得到調(diào)用。

2、構(gòu)造器內(nèi)部的多態(tài)方法的行為

構(gòu)造器調(diào)用的層次結(jié)構(gòu)帶來一個問題:如果在一個構(gòu)造器內(nèi)部調(diào)用正在構(gòu)造的對象的某個動態(tài)綁定方法,會發(fā)生什么?

public class Glyph {

    void draw() { print("Glyph.draw()"); }
    Glyph() {
        print("Glyph() before draw()");
        draw(); // 調(diào)用正在構(gòu)造的對象的某個動態(tài)綁定方法,對象的字段radius被初始化為0
        print("Glyph() after draw()");
    }

}


public class RoundGlyph extends Glyph{

    private int radius = 1;

    RoundGlyph(int r) {
        radius = r;
        print("RoundGlyph.RoundGlyph(), radius = " + radius);
    }
    void draw() {
        print("RoundGlyph.draw(), radius = " + radius);
    }


}


public class PolyConstructors {
    
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
    
}

/* Output:
    Glyph() before draw()
    RoundGlyph.draw(), radius = 0
    Glyph() after draw()
    RoundGlyph.RoundGlyph(), radius = 5
*///:~

Glyph的構(gòu)造器中,我們調(diào)用了draw方法,因為這個是動態(tài)綁定方法的緣故,我們就會調(diào)用導出類RoundGlyph中的draw方法,但是這個方法操縱的成員radius還沒初始化,所以就體現(xiàn)出問題了,結(jié)果中第一次輸出radius為0。

所以初始化的實際過程是:

  • 1 在其他任何事物之前,將分配給對象的存儲空間初始化成二進制的零
  • 2 如前所述調(diào)用基類構(gòu)造器
  • 3 按照聲明的順序調(diào)用成員的初始化方法
  • 4 調(diào)用導出類的構(gòu)造器主體

四、協(xié)變返回類型

在面向?qū)ο蟪绦蛟O計中,協(xié)變返回類型指的是子類中的成員函數(shù)的返回值類型不必嚴格等同于父類中被重寫的成員函數(shù)的返回值類型,而可以是更 "狹窄" 的類型。

​ Java 5.0添加了對協(xié)變返回類型的支持,即子類覆蓋(即重寫)基類方法時,返回的類型可以是基類方法返回類型的子類。協(xié)變返回類型允許返回更為具體的類型。

例子:

import java.io.ByteArrayInputStream;
import java.io.InputStream;

class Base
{
    //子類Derive將重寫此方法,將返回類型設置為InputStream的子類
   public InputStream getInput()
   {
      return System.in;
   }
}
public  class Derive extends Base
{

    @Override
    public ByteArrayInputStream getInput()
    {

        return new ByteArrayInputStream(new byte[1024]);
    }
    public static void main(String[] args)
    {
        Derive d=new Derive();
        System.out.println(d.getInput().getClass());
    }
}
/*程序輸出:
class java.io.ByteArrayInputStream
*/

五、繼承進行設計

class Actor {
 public void act() {
 }
}
 
class HappyActor extends Actor {
 public void act() {
  System.out.println("HappyActor");
 }
}
 
class SadActor extends Actor {
 public void act() {
  System.out.println("SadActor");
 }
}
 
class Stage {
 private Actor actor = new HappyActor();
 
 public void change() {
  actor = new SadActor();
 }
 
 public void performPlay() {
  actor.act();
 }
}
 
public class Transmogrify {
 public static void main(String[] args) {
  Stage stage = new Stage();
  stage.performPlay();
  stage.change();
  stage.performPlay();
 }
 
}

輸出:

  HappyActor
    SadActor

一條通用的準則是:“用繼承表達行為間的差異,并用字段表達狀態(tài)上的變化”。在上述例子中,兩者都用到了:通過繼承得到了兩個不同的類,用于表達 act()方法的差異:而 Stage通過運用組合使自己的狀態(tài)發(fā)生了變化。在這種情況下,這種狀態(tài)的改變也就產(chǎn)生了行為的改變。

總結(jié):

多態(tài)意味著 不同的形式。在面向?qū)ο蟮脑O計中,我們持有從基類繼承而來的相同接口,以及使用該接口的不同形式不同版本的多態(tài)綁定方法。 運用數(shù)據(jù)的抽象和繼承,能更好的類型和創(chuàng)造多態(tài)的例子。

到此這篇關于Java編程 多態(tài)的文章就介紹到這了,更多相關Java多態(tài)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java?如何接收kernel傳過來的數(shù)組(推薦)

    Java?如何接收kernel傳過來的數(shù)組(推薦)

    這篇文章主要介紹了Java?如何接收kernel傳過來的數(shù)組,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-08-08
  • 關于在Java中反轉(zhuǎn)數(shù)組的4種詳細方法

    關于在Java中反轉(zhuǎn)數(shù)組的4種詳細方法

    這篇文章主要介紹了關于在Java中反轉(zhuǎn)數(shù)組的4種詳細方法,數(shù)組是一個固定長度的存儲相同數(shù)據(jù)類型的數(shù)據(jù)結(jié)構(gòu),數(shù)組中的元素被存儲在一段連續(xù)的內(nèi)存空間中,今天我們來學習一下如何反轉(zhuǎn)數(shù)組
    2023-05-05
  • 深入了解Java設計模式之職責鏈模式

    深入了解Java設計模式之職責鏈模式

    Java設計模式中有很多種類別,例如單例模式、裝飾模式、觀察者模式等。本文將為大家詳細介紹其中的職責鏈模式,感興趣的可以了解一下
    2022-09-09
  • Spring Mvc中傳遞參數(shù)方法之url/requestMapping詳解

    Spring Mvc中傳遞參數(shù)方法之url/requestMapping詳解

    在開發(fā)中,參數(shù)傳遞是必不可少的一個功能,下面這篇文章主要給大家介紹了關于Spring Mvc中傳遞參數(shù)方法之url/requestMapping的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-07-07
  • 使用@Validated和@Valid 解決list校驗的問題

    使用@Validated和@Valid 解決list校驗的問題

    這篇文章主要介紹了使用@Validated和@Valid 解決list校驗的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • spring與disruptor集成的簡單示例

    spring與disruptor集成的簡單示例

    本篇文章主要介紹了spring與disruptor集成的簡單示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • SpringBoot集成JWT實現(xiàn)登陸驗證的方法詳解

    SpringBoot集成JWT實現(xiàn)登陸驗證的方法詳解

    JSON?Web?Token(JWT)是一個開放的標準(RFC?7519),它定義了一個緊湊且自包含的方式,用于在各方之間以JSON對象安全地傳輸信息。本文將利用SpringBoot集成JWT實現(xiàn)登陸驗證,感興趣的可以了解一下
    2022-05-05
  • 非常實用的java萬年歷制作方法

    非常實用的java萬年歷制作方法

    這篇文章主要為大家詳細介紹了非常實用的java萬年歷制作方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Hibernate管理Session和批量操作分析

    Hibernate管理Session和批量操作分析

    這篇文章主要介紹了Hibernate管理Session和批量操作的技巧,包括Hibernate管理Session、批量處理數(shù)據(jù)等的常用技巧及注意事項,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-12-12
  • Hibernate環(huán)境搭建與配置方法(Hello world配置文件版)

    Hibernate環(huán)境搭建與配置方法(Hello world配置文件版)

    這篇文章主要介紹了Hibernate環(huán)境搭建與配置方法,這里演示Hello world配置文件版的具體實現(xiàn)步驟與相關代碼,需要的朋友可以參考下
    2016-03-03

最新評論

搜索| 策勒县| 西城区| 洛川县| 周口市| 白朗县| 富宁县| 屏边| 农安县| 饶阳县| 天水市| 沙河市| 岑巩县| 龙南县| 伊川县| 怀来县| 荔浦县| 盘山县| 迁安市| 赤水市| 青阳县| 乡城县| 武川县| 南乐县| 杂多县| 江口县| 东港市| 会同县| 读书| 荣昌县| 太原市| 安徽省| 平武县| 麟游县| 长治县| 寿宁县| 赤壁市| 铜川市| 庆阳市| 利辛县| 平原县|