欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java超詳細(xì)講解繼承和多態(tài)的使用

 更新時(shí)間:2022年05月05日 17:18:58   作者:往日如風(fēng)_  
繼承就是可以直接使用前輩的屬性和方法。自然界如果沒(méi)有繼承,那一切都是處于混沌狀態(tài)。多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。多態(tài)就是同一個(gè)接口,使用不同的實(shí)例而執(zhí)行不同操作

繼承和多態(tài)

學(xué)習(xí)繼承、組合、多態(tài)

1、繼承

1.1、繼承概念

專門用來(lái)進(jìn)行共性抽取,實(shí)現(xiàn)代碼復(fù)用。 它允許程序員在保持原有類特 性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加新功能,這樣產(chǎn)生新的類,稱派生類。

1.2、繼承的語(yǔ)法

在Java中如果要表示類之間的繼承關(guān)系,需要借助extends關(guān)鍵字

class Animal{
    public String name;
    public int age;
    public String sex;
    public void eat(){
        System.out.println(this.name+"cat::eat()!");
    }
    public void sleep(){
        System.out.println(this.name+"睡覺(jué)!");
    }
}
/**
 * 繼承  其實(shí)就是對(duì)共性的抽取  從而達(dá)到了代碼的復(fù)用
 */
class Cat extends Animal{
    public void mew(){
        System.out.println(this.name+"cat::mew()!");
    }
}
class Dog extends Animal{
    public void bark(){
        System.out.println("dog::bark()!");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.name = "咪咪";
        cat.sleep();
        cat.eat();
        cat.mew();
    }
}

注意:

1. 子類會(huì)將父類中的成員變量或者成員方法繼承到子類中了

2. 子類繼承父類之后,盡量新添加自己特有的成員,體現(xiàn)出與基類的不同,否則就沒(méi)有必要繼承了

1.3、父類成員的訪問(wèn)

1.31、子類和父類不存在同名成員變量

public class Base {
    int a;
    int b;
}
public class Derived extends Base{
    int c;
    public void method(){
        a = 10;    // 訪問(wèn)從父類中繼承下來(lái)的a
        b = 20;    // 訪問(wèn)從父類中繼承下來(lái)的b
        c = 30;    // 訪問(wèn)子類自己的c
   }
}

1.32、子類和父類成員變量同名

class Base {
    public int a = 1;
    public int b = 2;
    public void method(){
        System.out.println("BASE::TEST()");
    }
}
class Derived extends Base{
    public int a = 3;
    public int d = 4;
    public void method2(){
        System.out.println("Derived::method2()");
    }
    public void test(){
        method2();
        method();
        /*System.out.println(a);//如果重名類  優(yōu)先訪問(wèn)自己的
        System.out.println(super.a);//寫代碼的時(shí)候  讓這個(gè)代碼更已讀
        System.out.println(this.b);
        System.out.println(d);*/
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.test();
    }
}

1、如果訪問(wèn)的成員變量子類中有,訪問(wèn)自己的成員變量。

2、如果訪問(wèn)的成員變量子類中無(wú),則訪問(wèn)父類繼承下來(lái)的,如果父類也沒(méi)有定義,則編譯報(bào)錯(cuò)。

3、如果訪問(wèn)的成員變量與父類中成員變量同名,則優(yōu)先訪問(wèn)自己的,即:子類將父類同名成員隱藏了。

4、成員變量訪問(wèn)遵循就近原則,自己有優(yōu)先自己的,如果沒(méi)有則向父類中找。

比如:你和你父親各自有一款相同的手機(jī),平時(shí)使用時(shí)你肯定優(yōu)先用自己的,如果自己手機(jī)沒(méi)電了,你才會(huì)考慮使用父親的。

1.33、成員方法名字不同

public class Base {
 public void methodA(){
     System.out.println("Base中的methodA()");
 }
}
public class Derived extends Base{
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
   }
    public void methodC(){
        methodB();         // 訪問(wèn)子類自己的methodB()
        methodA();         // 訪問(wèn)父類繼承的methodA()
        // methodD();     // 編譯失敗,在整個(gè)繼承體系中沒(méi)有發(fā)現(xiàn)方法methodD()
   }
}

總結(jié):成員方法沒(méi)有同名時(shí),在子類方法中或者通過(guò)子類對(duì)象訪問(wèn)方法時(shí),則優(yōu)先訪問(wèn)自己的,自己沒(méi)有時(shí) 再到父類中找,如果父類中也沒(méi)有則報(bào)錯(cuò)。

1.34、 成員方法名字相同

public class Base {
 public void methodA(){
     System.out.println("Base中的methodA()");
 }
 public void methodB(){
     System.out.println("Base中的methodB()");
 }
}
public class Derived extends Base{
    public void methodA(int a) {
        System.out.println("Derived中的method(int)方法");
   }
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
   }
    public void methodC(){
        methodA();      // 沒(méi)有傳參,訪問(wèn)父類中的methodA()
        methodA(20);    // 傳遞int參數(shù),訪問(wèn)子類中的methodA(int)
        methodB();      // 直接訪問(wèn),則永遠(yuǎn)訪問(wèn)到的都是子類中的methodB(),基類的無(wú)法訪問(wèn)到
   }
}

通過(guò)子類對(duì)象訪問(wèn)父類與子類中不同名方法時(shí),優(yōu)先在子類中找,找到則訪問(wèn),否則在父類中找,找到 則訪問(wèn),否則編譯報(bào)錯(cuò)。 通過(guò)派生類對(duì)象訪問(wèn)父類與子類同名方法時(shí),如果父類和子類同名方法的參數(shù)列表不同(重載),根據(jù)調(diào)用 方法適傳遞的參數(shù)選擇合適的方法訪問(wèn),如果沒(méi)有則報(bào)錯(cuò);如果父類和子類同名方法的原型一致,則只能訪問(wèn)到子類的,父類的無(wú)法通過(guò)派生類對(duì)象直接訪問(wèn)到。 問(wèn)題:如果子類中存在與父類中相同的成員時(shí),那如何在子類中訪問(wèn)父類相同名稱的成員呢?

1.4、super關(guān)鍵字

public class Base {
    int a;
    int b;
 public void methodA(){
     System.out.println("Base中的methodA()");
 }
 public void methodB(){
 System.out.println("Base中的methodB()");
 }
}
public class Derived extends Base{
    int a;    // 與父類中成員變量同名且類型相同
    char b;   // 與父類中成員變量同名但類型不同
    // 與父類中methodA()構(gòu)成重載
    public void methodA(int a) {
        System.out.println("Derived中的method()方法");
   }
    // 與基類中methodB()構(gòu)成重寫
    public void methodB(){
        System.out.println("Derived中的methodB()方法");
   }
    public void methodC(){
        // 對(duì)于同名的成員變量,直接訪問(wèn)時(shí),訪問(wèn)的都是子類的
        a = 100;   // 等價(jià)于: this.a = 100;
        b = 101;   // 等價(jià)于: this.b = 101;
        // 注意:this是當(dāng)前對(duì)象的引用
        // 訪問(wèn)父類的成員變量時(shí),需要借助super關(guān)鍵字
        // super是獲取到子類對(duì)象中從基類繼承下來(lái)的部分
        super.a = 200;
        super.b = 201;
        // 父類和子類中構(gòu)成重載的方法,直接可以通過(guò)參數(shù)列表區(qū)分清訪問(wèn)父類還是子類方法
        methodA();      // 沒(méi)有傳參,訪問(wèn)父類中的methodA()
        methodA(20);    // 傳遞int參數(shù),訪問(wèn)子類中的methodA(int)
        // 如果在子類中要訪問(wèn)重寫的基類方法,則需要借助super關(guān)鍵字
        methodB();      // 直接訪問(wèn),則永遠(yuǎn)訪問(wèn)到的都是子類中的methodB(),基類的無(wú)法訪問(wèn)到
        super.methodB(); // 訪問(wèn)基類的methodB()
   }
}

【注意事項(xiàng)】

1. 只能在非靜態(tài)方法中使用

2. 在子類方法中,訪問(wèn)父類的成員變量和方法。

1.5、子類構(gòu)造方法

父子父子,先有父再有子,即:子類對(duì)象構(gòu)造時(shí),需要先調(diào)用基類構(gòu)造方法,然后執(zhí)行子類的構(gòu)造方法。

public class Base {
public Base(){
        System.out.println("Base()");
 }
}
public class Derived extends Base{
   public Derived(){
       super();   // 注意子類構(gòu)造方法中默認(rèn)會(huì)調(diào)用基類的無(wú)參構(gòu)造方法:super(),
       // 用戶沒(méi)有寫時(shí),編譯器會(huì)自動(dòng)添加,而且super()必須是子類構(gòu)造方法中第一條語(yǔ)句,
       // 并且只能出現(xiàn)一次
       System.out.println("Derived()");
   }
}
public class Test {
    public static void main(String[] args) {
        Derived d = new Derived();
   }
}

結(jié)果打?。?br />Base()
Derived()

在子類構(gòu)造方法中,并沒(méi)有寫任何關(guān)于基類構(gòu)造的代碼,但是在構(gòu)造子類對(duì)象時(shí),先執(zhí)行基類的構(gòu)造方法,然后執(zhí)行子類的構(gòu)造方法,因?yàn)椋鹤宇悓?duì)象中成員是有兩部分組成的,基類繼承下來(lái)的以及子類新增加的部分 。父子父子 肯定是先有父再有子,所以在構(gòu)造子類對(duì)象時(shí)候 ,先要調(diào)用基類的構(gòu)造方法,將從基類繼承下來(lái)的成員構(gòu)造完整,然后再調(diào)用子類自己的構(gòu)造方法,將子類自己新增加的成員初始化完整 。

注意:

1. 若父類顯式定義無(wú)參或者默認(rèn)的構(gòu)造方法,在子類構(gòu)造方法第一行默認(rèn)有隱含的super()調(diào)用,即調(diào)用基類構(gòu)

造方法

2. 如果父類構(gòu)造方法是帶有參數(shù)的,此時(shí)編譯器不會(huì)再給子類生成默認(rèn)的構(gòu)造方法,此時(shí)需要用戶為子類顯式

定義構(gòu)造方法,并在子類構(gòu)造方法中選擇合適的父類構(gòu)造方法調(diào)用,否則編譯失敗。

3. 在子類構(gòu)造方法中,super(…)調(diào)用父類構(gòu)造時(shí),必須是子類構(gòu)造函數(shù)中第一條語(yǔ)句。

4. super(…)只能在子類構(gòu)造方法中出現(xiàn)一次,并且不能和this同時(shí)出現(xiàn)

1.6、super和this

【相同點(diǎn)】

1. 都是Java中的關(guān)鍵字

2. 只能在類的非靜態(tài)方法中使用,用來(lái)訪問(wèn)非靜態(tài)成員方法和字段

3. 在構(gòu)造方法中調(diào)用時(shí),必須是構(gòu)造方法中的第一條語(yǔ)句,并且不能同時(shí)存在

【不同點(diǎn)】

1. this是當(dāng)前對(duì)象的引用,當(dāng)前對(duì)象即調(diào)用實(shí)例方法的對(duì)象,super相當(dāng)于是子類對(duì)象中從父類繼承下來(lái)部分成員的引用

2. 在非靜態(tài)成員方法中,this用來(lái)訪問(wèn)本類的方法和屬性,super用來(lái)訪問(wèn)父類繼承下來(lái)的方法和屬性

3. this是非靜態(tài)成員方法的一個(gè)隱藏參數(shù),super不是隱藏的參數(shù)

4. 成員方法中直接訪問(wèn)本類成員時(shí),編譯之后會(huì)將this還原,即本類非靜態(tài)成員都是通過(guò)this來(lái)訪問(wèn)的;在子類中如果通過(guò)super訪問(wèn)父類成員,編譯之后在字節(jié)碼層面super實(shí)際是不存在的

5. 在構(gòu)造方法中:this(…)用于調(diào)用本類構(gòu)造方法,super(…)用于調(diào)用父類構(gòu)造方法,兩種調(diào)用不能同時(shí)在構(gòu)造方法中出現(xiàn)

6. 構(gòu)造方法中一定會(huì)存在super(…)的調(diào)用,用戶沒(méi)有寫編譯器也會(huì)增加,但是this(…)用戶不寫則沒(méi)有

1.7、初始化

class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("構(gòu)造方法執(zhí)行");
   }
   {
        System.out.println("實(shí)例代碼塊執(zhí)行");
   }
    static {
        System.out.println("靜態(tài)代碼塊執(zhí)行");
        }
}
public class TestDemo {
    public static void main(String[] args) {
        Person person1 = new Person("bit",10);
        System.out.println("============================");
        Person person2 = new Person("gaobo",20);
   }
}

執(zhí)行結(jié)果:
靜態(tài)代碼塊執(zhí)行
實(shí)例代碼塊執(zhí)行
構(gòu)造方法執(zhí)行
============================
實(shí)例代碼塊執(zhí)行
構(gòu)造方法執(zhí)行

注意:

1. 靜態(tài)代碼塊先執(zhí)行,并且只執(zhí)行一次,在類加載階段執(zhí)行

2. 當(dāng)有對(duì)象創(chuàng)建時(shí),才會(huì)執(zhí)行實(shí)例代碼塊,實(shí)例代碼塊執(zhí)行完成后,最后構(gòu)造方法執(zhí)行

繼承關(guān)系上的執(zhí)行順序:

1、父類靜態(tài)代碼塊優(yōu)先于子類靜態(tài)代碼塊執(zhí)行,且是最早執(zhí)行

2、父類實(shí)例代碼塊和父類構(gòu)造方法緊接著執(zhí)行

3、子類的實(shí)例代碼塊和子類構(gòu)造方法緊接著再執(zhí)行

4、第二次實(shí)例化子類對(duì)象時(shí),父類和子類的靜態(tài)代碼塊都將不會(huì)再執(zhí)行

1.8、protected關(guān)鍵字

// 為了掩飾基類中不同訪問(wèn)權(quán)限在子類中的可見(jiàn)性,為了簡(jiǎn)單類B中就不設(shè)置成員方法了
// extend01包中
public class B {
    private int a;
    protected int b;
    public int c;
    int d;
}
// extend01包中
// 同一個(gè)包中的子類
public class D extends B{
    public void method(){
        // super.a = 10;     // 編譯報(bào)錯(cuò),父類private成員在相同包子類中不可見(jiàn)
        super.b = 20;         // 父類中protected成員在相同包子類中可以直接訪問(wèn)
        super.c = 30;         // 父類中public成員在相同包子類中可以直接訪問(wèn)
        super.d = 40;         // 父類中默認(rèn)訪問(wèn)權(quán)限修飾的成員在相同包子類中可以直接訪問(wèn)
   }
}
// extend02包中
// 不同包中的子類
public class C extends B {
    public void method(){
        // super.a = 10;     // 編譯報(bào)錯(cuò),父類中private成員在不同包子類中不可見(jiàn)
        super.b = 20;        // 父類中protected修飾的成員在不同包子類中可以直接訪問(wèn)
        super.c = 30;        // 父類中public修飾的成員在不同包子類中可以直接訪問(wèn)
        //super.d = 40;     // 父類中默認(rèn)訪問(wèn)權(quán)限修飾的成員在不同包子類中不能直接訪問(wèn)
   }
}
// extend02包中
// 不同包中的類
public class TestC {
    public static void main(String[] args) {
        C c = new C();
         c.method();
        // System.out.println(c.a);   // 編譯報(bào)錯(cuò),父類中private成員在不同包其他類中不可見(jiàn)
        // System.out.println(c.b);   // 父類中protected成員在不同包其他類中不能直接訪問(wèn)
        System.out.println(c.c);      // 父類中public成員在不同包其他類中可以直接訪問(wèn)
        // System.out.println(c.d);   // 父類中默認(rèn)訪問(wèn)權(quán)限修飾的成員在不同包其他類中不能直接訪問(wèn)
   }
}

注意:父類中private成員變量隨時(shí)在子類中不能直接訪問(wèn),但是也繼承到子類中了

1.9、繼承方式

1.10、final關(guān)鍵字

final關(guān)鍵可以用來(lái)修飾變量、成員方法以及類。

1. 修飾變量或字段,表示常量(即不能修改)

2. 修飾類:表示此類不能被繼承

2、繼承與組合

組合表示對(duì)象之間的關(guān)系

// 輪胎類
class Tire{
    // ...
}
// 發(fā)動(dòng)機(jī)類
class Engine{
    // ...
}
// 車載系統(tǒng)類
class VehicleSystem{
    // ...
}
class Car{
    private Tire tire;          // 可以復(fù)用輪胎中的屬性和方法
    private Engine engine;      // 可以復(fù)用發(fā)動(dòng)機(jī)中的屬性和方法
    private VehicleSystem vs;   // 可以復(fù)用車載系統(tǒng)中的屬性和方法
    // ...
}
// 奔馳是汽車
class Benz extend Car{
    // 將汽車中包含的:輪胎、發(fā)送機(jī)、車載系統(tǒng)全部繼承下來(lái)
}

3、多態(tài)

3.1、多態(tài)概念

通俗來(lái)說(shuō),就是多種形態(tài),具體點(diǎn)就是去完成某個(gè)行為,當(dāng)不同的對(duì)象去完成時(shí)會(huì)產(chǎn)生出不同 的狀態(tài)。

3.2、多態(tài)實(shí)現(xiàn)條件

1. 必須在繼承體系下

2. 子類必須要對(duì)父類中方法進(jìn)行重寫

3. 通過(guò)父類的引用調(diào)用重寫的方法

public class Animal {
String name;
    int age;
    public Animal(String name, int age){
        this.name = name;
        this.age = age;
   }
    public void eat(){
        System.out.println(name + "吃飯");
   }
}
public class Cat extends Animal{
    public Cat(String name, int age){
        super(name, age);
   }
    @Override
    public void eat(){
        System.out.println(name+"吃魚~~~");
   }
}
public class Dog extends Animal {
    public Dog(String name, int age){
        super(name, age);
   }
    @Override
    public void eat(){
        System.out.println(name+"吃骨頭~~~");
   }
}
///分割線//
public class TestAnimal {
    // 編譯器在編譯代碼時(shí),并不知道要調(diào)用Dog 還是 Cat 中eat的方法
    // 等程序運(yùn)行起來(lái)后,形參a引用的具體對(duì)象確定后,才知道調(diào)用那個(gè)方法
    // 注意:此處的形參類型必須時(shí)父類類型才可以
    public static void eat(Animal a){
        a.eat();
   }
    public static void main(String[] args) {
        Cat cat = new Cat("元寶",2);
        Dog dog = new Dog("小七", 1);
        eat(cat);
        eat(dog);
   }
}

運(yùn)行結(jié)果:
元寶吃魚~~~
元寶正在睡覺(jué)
小七吃骨頭~~~
小七正在睡覺(jué)

3.3、重寫

重寫(override):也稱為覆蓋。重寫是子類對(duì)父類非靜態(tài)、非private修飾,非final修飾,非構(gòu)造方法等的實(shí)現(xiàn)過(guò)程進(jìn)行重新編寫, 返回值和形參都不能改變。即外殼不變,核心重寫!重寫的好處在于子類可以根據(jù)需要,定義特定于自己的行為。 也就是說(shuō)子類能夠根據(jù)需要實(shí)現(xiàn)父類的方法。

1. 子類在重寫父類的方法時(shí),一般必須與父類方法原型一致:修飾符 返回值類型 方法名(參數(shù)列表) 要完全一致

2. JDK7以后,被重寫的方法返回值類型可以不同,但是必須是具有父子關(guān)系的

訪問(wèn)權(quán)限不能比父類中被重寫的方法的訪問(wèn)權(quán)限更低。例如:如果父類方法被public修飾,則子類中重寫該方法就不能聲明為 protected

3. 父類被static、private修飾的方法、構(gòu)造方法都不能被重寫。

子類和父類在同一個(gè)包中,那么子類可以重寫父類所有方法,除了聲明為 private 和 final 的方法。

4. 子類和父類不在同一個(gè)包中,那么子類只能夠重寫父類的聲明為 public 和 protected 的非 final 方法。

5. 重寫的方法, 可以使用 @Override 注解來(lái)顯式指定. 有了這個(gè)注解能幫我們進(jìn)行一些合法性校驗(yàn). 例如不小心將方法名字拼寫錯(cuò)了 (比如寫成 aet), 那么此時(shí)編譯器就會(huì)發(fā)現(xiàn)父類中沒(méi)有 aet 方法, 就會(huì)編譯報(bào)錯(cuò), 提示無(wú)法構(gòu)成重寫.

重載與重寫區(qū)別:

方法重載是一個(gè)類的多態(tài)性表現(xiàn),而方法重寫是子類與父類的一種多態(tài)性表現(xiàn)。

3.4、向上轉(zhuǎn)型和向下轉(zhuǎn)型

向上轉(zhuǎn)型:實(shí)際就是創(chuàng)建一個(gè)子類對(duì)象,將其當(dāng)成父類對(duì)象來(lái)使用。

語(yǔ)法格式:父類類型 對(duì)象名 = new 子類類型()

【使用場(chǎng)景】

1. 直接賦值

2. 方法傳參

3. 方法返回

public class TestAnimal {
    // 2. 方法傳參:形參為父類型引用,可以接收任意子類的對(duì)象
    public static void eatFood(Animal a){
        a.eat();
   }
    // 3. 作返回值:返回任意子類對(duì)象
    public static Animal buyAnimal(String var){
        if("狗" == var){
            return new Dog("狗狗",1);
       }else if("貓" == var){
            return new Cat("貓貓", 1);
       }else{
            return null;
       }
   }
    public static void main(String[] args) {
        Animal cat = new Cat("元寶",2);   // 1. 直接賦值:子類對(duì)象賦值給父類對(duì)象
        Dog dog = new Dog("小七", 1);
        eatFood(cat);
        eatFood(dog);
        Animal animal = buyAnimal("狗");
        animal.eat();
        animal = buyAnimal("貓");
        animal.eat();
   }
}

將一個(gè)子類對(duì)象經(jīng)過(guò)向上轉(zhuǎn)型之后當(dāng)成父類方法使用,再無(wú)法調(diào)用子類的方法,但有時(shí)候可能需要調(diào)用子類特有的

方法,此時(shí):將父類引用再還原為子類對(duì)象即可,即向下轉(zhuǎn)換。

public class TestAnimal {
    public static void main(String[] args) {
        Cat cat = new Cat("元寶",2);
        Dog dog = new Dog("小七", 1);
        // 向上轉(zhuǎn)型
        Animal animal = cat;
        animal.eat();
        animal = dog;
        animal.eat();
        // 編譯失敗,編譯時(shí)編譯器將animal當(dāng)成Animal對(duì)象處理
        // 而Animal類中沒(méi)有bark方法,因此編譯失敗
        // animal.bark();
        // 向上轉(zhuǎn)型
        // 程序可以通過(guò)編程,但運(yùn)行時(shí)拋出異常---因?yàn)椋篴nimal實(shí)際指向的是狗
        // 現(xiàn)在要強(qiáng)制還原為貓,無(wú)法正常還原,運(yùn)行時(shí)拋出:ClassCastException
        cat = (Cat)animal;
        cat.mew();
        // animal本來(lái)指向的就是狗,因此將animal還原為狗也是安全的   
        dog = (Dog)animal;
        dog.bark();
   }
}

向下轉(zhuǎn)型用的比較少,而且不安全,萬(wàn)一轉(zhuǎn)換失敗,運(yùn)行時(shí)就會(huì)拋異常。Java中為了提高向下轉(zhuǎn)型的安全性,引入

了 instanceof ,如果該表達(dá)式為true,則可以安全轉(zhuǎn)換。

public class TestAnimal {
    public static void main(String[] args) {
        Cat cat = new Cat("元寶",2);
        Dog dog = new Dog("小七", 1);
        // 向上轉(zhuǎn)型
        Animal animal = cat;
          animal.eat();
        animal = dog;
        animal.eat();
        if(animal instanceof Cat){
            cat = (Cat)animal;
            cat.mew();
       }
        if(animal instanceof Dog){
            dog = (Dog)animal;
            dog.bark();
       }
   }
}

3.5、多態(tài)優(yōu)缺點(diǎn)

【使用多態(tài)的好處】

1. 能夠降低代碼的 “圈復(fù)雜度”, 避免使用大量的 if - else

就曉得了什么叫 “圈復(fù)雜度” ?那么我們來(lái)對(duì)比一下

這是if-else分支語(yǔ)句:

public static void drawShapes() {
    Rect rect = new Rect();
    Cycle cycle = new Cycle();
    Flower flower = new Flower();
    String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
    
    for (String shape : shapes) {
        if (shape.equals("cycle")) {
            cycle.draw();
       } else if (shape.equals("rect")) {
            rect.draw();
       } else if (shape.equals("flower")) {
            flower.draw();
       }
   }
}

如果使用使用多態(tài):

public static void drawShapes() {
    // 我們創(chuàng)建了一個(gè) Shape 對(duì)象的數(shù)組. 
    Shape[] shapes = {new Cycle(), new Rect(), new Cycle(), 
                      new Rect(), new Flower()};
    for (Shape shape : shapes) {
        shape.draw();
   }
}

2. 可擴(kuò)展能力更強(qiáng)

如果要新增一種新的形狀, 使用多態(tài)的方式代碼改動(dòng)成本也比較低.

class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("△");
   }
}

對(duì)于類的調(diào)用者來(lái)說(shuō)(drawShapes方法), 只要?jiǎng)?chuàng)建一個(gè)新類的實(shí)例就可以了, 改動(dòng)成本很低. 而對(duì)于不用多態(tài)的情況, 就要把drawShapes 中的 if - else 進(jìn)行一定的修改, 改動(dòng)成本更高.

多態(tài)缺陷:代碼的運(yùn)行效率降低。

3.6、避免在構(gòu)造方法中調(diào)用重寫的方法

我們創(chuàng)建兩個(gè)類, B 是父類, D 是子類. D 中重寫 func 方法. 并且在 B 的構(gòu)造方法中調(diào)用 func

class B {
    public B() {
        // do nothing
        func();
   }
    public void func() {
        System.out.println("B.func()");
   }
}
class D extends B {
    private int num = 1;
    @Override
    public void func() {
        System.out.println("D.func() " + num);
   }
}
public class Test {
    public static void main(String[] args) {
        D d = new D();
        }
}

執(zhí)行結(jié)果
D.func() 0

1. 構(gòu)造 D 對(duì)象的同時(shí), 會(huì)調(diào)用 B 的構(gòu)造方法.

2. B 的構(gòu)造方法中調(diào)用了 func 方法, 此時(shí)會(huì)觸發(fā)動(dòng)態(tài)綁定, 會(huì)調(diào)用到 D 中的 func此時(shí) D 對(duì)象自身還沒(méi)有構(gòu)造, 此時(shí) num 處在未初始化的狀態(tài), 值為 0.

結(jié)論: “用盡量簡(jiǎn)單的方式使對(duì)象進(jìn)入可工作狀態(tài)”, 盡量不要在構(gòu)造器中調(diào)用方法(如果這個(gè)方法被子類重寫, 就會(huì)觸 發(fā)動(dòng)態(tài)綁定,

但是此時(shí)子類對(duì)象還沒(méi)構(gòu)造完成), 可能會(huì)出現(xiàn)一些隱藏的但是又極難發(fā)現(xiàn)的問(wèn)題.

到此這篇關(guān)于Java超詳細(xì)講解繼承和多態(tài)的使用的文章就介紹到這了,更多相關(guān)Java繼承和多態(tài)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11的解決方法

    IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11的解決方法

    這篇文章主要介紹了IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java數(shù)據(jù)結(jié)構(gòu)超詳細(xì)分析二叉搜索樹

    Java數(shù)據(jù)結(jié)構(gòu)超詳細(xì)分析二叉搜索樹

    二叉搜索樹是以一棵二叉樹來(lái)組織的。每個(gè)節(jié)點(diǎn)是一個(gè)對(duì)象,包含的屬性有l(wèi)eft,right,p和key,其中,left指向該節(jié)點(diǎn)的左孩子,right指向該節(jié)點(diǎn)的右孩子,p指向該節(jié)點(diǎn)的父節(jié)點(diǎn),key是它的值
    2022-03-03
  • Java圖形用戶界面設(shè)計(jì)(Swing)的介紹

    Java圖形用戶界面設(shè)計(jì)(Swing)的介紹

    看到多數(shù)人提到 Java 就以為是網(wǎng)絡(luò)開發(fā),其實(shí)不是這樣的,Java 也可以開發(fā)應(yīng)用程序,而且可以開發(fā)出漂亮的圖形用戶界面的應(yīng)用程序,因此,我寫下這篇文章,希望能帶你進(jìn)入 Java 圖形用戶界面設(shè)計(jì)之門。
    2016-07-07
  • java EasyExcel實(shí)現(xiàn)動(dòng)態(tài)列解析和存表

    java EasyExcel實(shí)現(xiàn)動(dòng)態(tài)列解析和存表

    這篇文章主要為大家介紹了java EasyExcel實(shí)現(xiàn)動(dòng)態(tài)列解析和存表示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Spring實(shí)現(xiàn)郵件發(fā)送功能

    Spring實(shí)現(xiàn)郵件發(fā)送功能

    這篇文章主要為大家詳細(xì)介紹了Spring實(shí)現(xiàn)郵件發(fā)送功能,簡(jiǎn)單的發(fā)送郵件工具JavaMailSender使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java ArrayList遍歷修改代碼實(shí)例解析

    Java ArrayList遍歷修改代碼實(shí)例解析

    這篇文章主要介紹了Java ArrayList遍歷修改代碼實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 使用spring框架中的組件發(fā)送郵件功能說(shuō)明

    使用spring框架中的組件發(fā)送郵件功能說(shuō)明

    Spring使用的是基本的JavaBean來(lái)完成以前只可能由EJB完成的事情。這篇文章主要介紹了使用spring框架中的組件發(fā)送郵件,需要的朋友可以參考下
    2017-11-11
  • 與眾不同的 Java 日期格式化大全

    與眾不同的 Java 日期格式化大全

    這篇文章主要介紹了與眾不同的 Java 日期格式化大全,在 Java 中,經(jīng)常要將時(shí)間字符串轉(zhuǎn)換為日期,或者要將日期轉(zhuǎn)換為時(shí)間字符串。,需要的朋友可以參考下
    2019-06-06
  • springboot 中異步任務(wù),定時(shí)任務(wù),郵件任務(wù)詳解

    springboot 中異步任務(wù),定時(shí)任務(wù),郵件任務(wù)詳解

    這篇文章主要介紹了springboot 與異步任務(wù),定時(shí)任務(wù),郵件任務(wù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • Java界面編程實(shí)現(xiàn)界面跳轉(zhuǎn)

    Java界面編程實(shí)現(xiàn)界面跳轉(zhuǎn)

    這篇文章主要為大家詳細(xì)介紹了Java界面編程實(shí)現(xiàn)界面跳轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論