java多態(tài)之簡述

Java的第三大特性------>多態(tài)

一、什么是多態(tài)

多態(tài)根據(jù)其字面意思就是多種形態(tài)的意思,那么在Java中的多態(tài)指的是什么呢?

指的是對象具有多種形態(tài)的意思,只是Java中分為引用多態(tài)和方法多態(tài)

A.引用多態(tài)

a.父類的引用指向本類的對象

b.父類的引用指向子類的對象

如下圖所示可以看出來,父類Animal_manStyle的引用指向了本身,還可以指向子類的對象,

但是子類的引用不可以指向父類的對象。

這就好比貓是動物,但動物不一定是貓啊

image
image
image

B.方法多態(tài)

a.父類的對象可以調(diào)用本身的方法

b.父類指向子類的對象,那么調(diào)用的時候就是調(diào)用的子類的方法(子類重寫了父類的方法),如果子類沒有重寫父類的方法,那么子類對象調(diào)用的就是父類的對象

如上圖的調(diào)用,a是父類的對象引用,c是子類的對象引用,結(jié)果如下

image

注意:多態(tài)是基于繼承的,但是有一種情況下是不能使用多態(tài)的,便是父類指向的引用不能指向子類獨(dú)有的方法

image

image

二、多態(tài)之引用類型轉(zhuǎn)換

引用類型轉(zhuǎn)換分為兩種轉(zhuǎn)換,一種是自動類型轉(zhuǎn)換,二是強(qiáng)制類型轉(zhuǎn)換

A.自動類型轉(zhuǎn)換又稱為向上類型提升

image

Bus類是Transportation的子類,即 父類的引用可以指向其子類(小類型轉(zhuǎn)換成大類型),上圖就是自動類型轉(zhuǎn)換。

B.強(qiáng)制類型轉(zhuǎn)換又稱為向下類型轉(zhuǎn)換,存在一定的風(fēng)險

image
image

上圖可以看出來,當(dāng)一個父類型的引用指向一個子類型的對象時,可以對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換,為了避免類型轉(zhuǎn)換時出現(xiàn)的不安全為問題,我們利用 instanceof關(guān)鍵字,instanceof關(guān)鍵字是判斷這個引用是否是這個類的,即 car 引用是否是Car類型的或者是Car的子類型的,

當(dāng)if中的判斷成立的話,我們就可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換,并且不會出錯。

其實強(qiáng)制類型轉(zhuǎn)換的根本就是,當(dāng)利用構(gòu)造器構(gòu)造出來的對象在內(nèi)存中本身已經(jīng)有一個類型,如果要賦予的引用是這個類型的或者是其父類型的則可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換,如

      Animal  animal = new Dog();

    Dog  dog=(Dog)animal;

animal 在內(nèi)存中本身就是Dog類型的,所以對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換成Dog是可以的

但是,

  Animal animal = new Animal();

  Dog dog = (Dog) animal;

這個是不行的,因為animal 在內(nèi)存中本身是Animal 類型的,現(xiàn)在對它進(jìn)行的轉(zhuǎn)換不是它本類,或者是它的父類,所以這個是不可以進(jìn)行類型轉(zhuǎn)換的,編譯器會通過,但是運(yùn)行時會拋出ClassCastException異常

同樣還有一種情況是不可以的,如下:

  Animal   dog = new Dog();

  Cat    cat  =(Cat)dog;

這里的Cat 是繼承自Animal 的,但是同樣不可以,因為dog 的本身是Dog類型,不是同級的Cat類型。

三、多態(tài)之抽象類

  A.什么是抽象類

抽象類就是不能具體的表示一個對象的類,比如動物,它不可能是一個具體的對象,要是想清楚的表示一個對象,那么必須由他的子類貓或者狗來表示

B.怎么描述一個抽象類

a.前面必須有關(guān)鍵字abstract 來修飾

b.抽象類中包含抽象方法,抽象方法沒有方法體,必須由子類來實現(xiàn)

c.體現(xiàn)了數(shù)據(jù)抽象的思想,是實現(xiàn)多態(tài)的一種機(jī)制

d.抽象類不能被實例化,它有的只是指向子類對象的引用

e.從多個類中抽象出一個抽象類,作為子類設(shè)計的模板,從而限制了子類設(shè)計的隨意性

f.不關(guān)心子類的具體實現(xiàn),只關(guān)注子類中必須有什么方法

g. abstract不能和final同時修飾一個類

h.abstract 不能與private 、static 、final 等共同修飾同一個方法

抽象類為Telphone,子類是 CellPhone ,SmartPhone,那么代碼如下:

public abstract  class Telphone {
    public abstract  void call();
    public abstract   void message();
    public void printf(){
        System.out.println("Hello_abstractClass");
    }
}

public class CellPhone extends Telphone{
  @Override
    public void call(){
        System.out.println("cellPhone電話具有打電話的功能");
    }

    @Override
    public void message() {
        System.out.println("CellPhone具有發(fā)短信的功能");
    }

    public void inter(){
        System.out.println("可以上網(wǎng)");
    }

}

public class SmartPhone extends Telphone{
    @Override
    public void call() {
        System.out.println("SmartPhone具有打電話的功能");
    }

    @Override
    public void message() {
        System.out.println("SmartPhone具有發(fā)短信的功能");
    }

    @Override
    public void printf() {
        super.printf();
        System.out.println("可以輸出");
    }
}

public class Initail {
    public static void main(String[] args){
        Telphone tel1=new CellPhone();
        Telphone tel2=new SmartPhone();
        CellPhone  tel3=new CellPhone();
        CellPhone  tel4=(CellPhone) tel1;
        tel4.inter();
        tel3.inter();
        tel1.call();
        tel1.message();
        tel1.printf();
        tel2.call();
        tel2.message();
        tel2.printf();
    }
}

從這段代碼中可以看出來抽象類的引用指向了子類的對象,并且可以調(diào)用子類實現(xiàn)的方法,但是有一點就是當(dāng)子類中的獨(dú)有方法時,父類的引用是不可以調(diào)用的,惟有子類的引用可以調(diào)用。如上圖的inter()方法。

四、多態(tài)之接口

A.什么是接口

接口是一組規(guī)范,并不關(guān)心類的具體的數(shù)據(jù)與實現(xiàn),只是規(guī)定了類該實現(xiàn)哪些方法,是用來約束類的,

B. 怎么描述接口

a.接口是一個特殊的類,其中可以是公共的常量和公共的抽象方法組成

b.使用interface關(guān)鍵字定義接口

c.是public abstract(可以有,沒有顯示出現(xiàn)的話,會被隱式添加上)

d.接口是可以多繼承的,它可以繼承多個父接口

如:

  修飾符  (abstract)   接口名 [ extends   父接口1 ,父接口2,....]
  {
      0~n個常量
      0~n個抽象方法的定義  
  }

e.接口中是常量,修飾符是public static final ,如果沒有寫,系統(tǒng)會隱式的添加

f.定義方法時修飾是public abstract,如果沒有添加,那么系統(tǒng)會自動添加

g.一個類可以實現(xiàn)一個或多個接口,多個接口之間使用,分隔開來,使用implements實現(xiàn)接口

h.在繼承一個類的同時也可以實現(xiàn)接口,但是繼承的類必須在實現(xiàn)接口之前

如:

修飾符 class 類名 extends 父類 implements 接口1, 接口 2...

public abstract interface IplayGame{
    public static final int IGrade=1;//可以在接口中定義常量

    public void playGame();

}

public class CellPhone extends Telphone implements IplayGame{
    public void call(){
        System.out.println("cellPhone電話具有打電話的功能");
    }

    @Override
    public void message() {
        System.out.println("CellPhone具有發(fā)短信的功能");
    }

    public void inter(){
        System.out.println("可以上網(wǎng)");
    }

    @Override
    public void playGame() {
        System.out.println("CellPhone 不能打游戲");
    }
}

public class initail {
         public static void main(String[] args){
((CellPhone) tel1).playGame();
        System.out.println(CellPhone.IGrade);
    }
}

在這段代碼中,有一個接口IplayGame,CellPhone 實現(xiàn)了IplayGame這個接口,然后用了CellPhone 的引用調(diào)用這個接口中的常量和方法。

I.使用匿名內(nèi)部類實現(xiàn)接口

IplayGame  ip1= new IplayGame() {
            @Override
            public void playGame() {
                System.out.println("使用匿名內(nèi)部類實現(xiàn)接口");
            }
        };
        ip1.playGame();

        new IplayGame() {
            @Override
            public void playGame() {
                System.out.println("使用匿名內(nèi)部類實現(xiàn)了接口2");        
            }
        }.playGame();

在匿名內(nèi)部類中可以直接new 一個接口的引用,后來可以用接口的引用直接調(diào)用我們的接口內(nèi)的方法。個人覺得這個就像是在接口中實現(xiàn)了抽象方法,然后利用接口的引用調(diào)用了被實現(xiàn)的方法,這個接口就相當(dāng)于一個類(如有不對的,還請多多指教!!!).

多態(tài)的就總結(jié)到這兒,下面簡單的說一下接口和抽象類的區(qū)別:

1.關(guān)鍵字不同

2.接口中不能有被實現(xiàn)了的方法,抽象類中可以有

3.接口可以實現(xiàn)多繼承,抽象類只能單繼承

4.接口中只能是成員常量,抽象類中可以成員變量

5.繼承抽象類的子類必須和抽象類本身有繼承關(guān)系,則存在 is a的關(guān)系,但是實現(xiàn)接口不一定,只要能夠?qū)崿F(xiàn)接口中定義的方法即可

每天總結(jié)一點點,堅持

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容