Java-4-重載多態

Ø 課堂討論要點:

 

1.重載 (overload)

 

   一個類中,可以存在多個同名的方法。在傳統的面向過程的編程語言中,方法名不能雷同,那麼一個方法名被使用後,將不能在別的地方被利用,有的時候,一個方法名確實很好用,能夠精確表達某個方法的含義,如果不能被重用,就會導致方法名資源的浪費,造成了編程的複雜性

 

   方法名相同,參數不同,則構成方法的重載,系統將根據你在方法調用過程中,所傳進來的參數的數據類型,選擇並執行對應的方法。

 

   參數不同則構成重載,具體規則如下:

   1. 參數數量不同

   2.  對應參數位置的參數數據類型不同

   

   案例:

int add( int a , int b);      

int add( int a, int b, int c);

int add( int a, double c); 

int add( int a, int d);   

    [參數名不列入重載考慮範圍,構成重名]

    void add( int a, int b);

        [返回值不列入重載考慮範圍,構成重名]

    Public int add(int a, int b);

        [訪問修飾符不列入重載考慮範圍,構成重名]

    

編譯器本質上是不允許方法重名的,這在面向對象編程語言中也是這樣的, 在程序員的呼籲中,編譯器的開發者提供了能夠名字重複使用的機制,但編譯器最終將把方法名做修正,比如:

int add( int a , int b);         à  add_int_int

int add( int a, int b, int c);    à  add_int_int_int

 

繼承環境下,子類即可以重寫父類方法,也可以重載父類方法。

在本類中,只能重載,如果出現類似重寫的效果,即判斷爲錯誤,認定爲重名。

 

選擇題:

1. public class MethodOver {

2. public void setVar (int a, int b, float c) {

3. }

4. }

Which two overload the setVar method? (Choose Two)

A. private void setVar (int a, float c, int b) { }

B. protected void setVar (int a, int b, float c) { }

C. public int setVar (int a, float c, int b) (return a;)

D. public int setVar (int a, int b, float c) (return a;)

E. protected float setVar (int a, int b, float c) (return c;)

 

2. 重寫 (override

 

在繼承環境下,子類認可父類的行爲 (認同和堅持方法的簽名),但對行爲的具體執行過程不認可,則決定對父親這個方法進行局部或者完全的更新。

 

重寫的模式從內容實現上分爲2種:

1) 改良性,補充型重寫:對父親提供的方法內容進行補充。

2) 顛覆性重寫:完全否定父親所提供的方法內容,徹底改寫。

 

    重寫不是覆蓋掉父親的方法,父親該方法在子類內部還是存在的。在內存中,體現爲子類和父類兩個同簽名方法共存的現象。在子類方法中,可以通過super.來顯示調用父類被重寫的方法,如果不用super. ,則表示調用子類的重寫方法。

 

    繼承環境下子類方法設置的可能情況:

 

     Class A{

      void sayHello(int a, int b)
}

 

Class B extends A

 

     Void sayHello(int a, int b){ //在子類中,出現和父類方法同簽名,則爲重寫

      ........

     }

 

     Void tellYouSomething(int a){ //方法名和所有父類方法均不同,稱爲子類自定義新方法

     

     }

 

     Void sayHello(int a, int b, int c){ //子類對父類方法的簽名做部分改造,叫做跨類重載

  

     }

   

    3. 多態 (polymorphism)

    

a. 多態三要素

1) 在繼承環境下,子類重寫父類方法。

2) 通過父類引用變量指向子類對象。

3) 恰好通過父類引用變量調用的是被重寫的方法。

       

       在此情況下,將發生多態效應,從常態來說,通過父類引用變量指向子類對象,該引用變量只能看到子類對象中的父類部分,不可能調用到子類方法。但是由於這裏存在重寫,通過父類引用變量向子類對象發送信號的時候,該方法調用信號由於和子類重寫方法簽名是完全一致,結果調用子類的該重寫方法,對於方法的主調者來說,其並不知道會產生這個結果,純屬意外。

 

b. 多態的用途

爲今後編寫框架代碼提供了可能,適合用來編寫通用底層代碼。

 

    public static void main(String[] args) {

Mouse mouse=new Mouse();

Tiger tiger=new Tiger();

//mouse.sound();

//tiger.sound();

//Animal a=new Tiger();

//a.sound();

letAnimalSound(new Tiger());

letAnimalSound(new Mouse());

letAnimalSound(new Sheep());

 

   }

    static void letAnimalSound(Animal a){

  a.sound();

}

 

4. 不定參數 (…)

 double add(int a, int b, double... m){

 double sum=a+b;

 

 for(int i=0;i<m.length;i++)

 sum=sum+m[i];

 

 return sum;

 

}

 

不定參數是爲了方便參數數量不確定的情況,以提高方法簽名的高度兼容性。

M最終將會被理解爲 double[], 

 

一個方法簽名的不定參數只能有一個,而且是最後一個。

 

int add(int ... n){

 

 int sum=0;

 

 for(int x:n)   //for…each循環

sum=sum+x;

 

 return sum;

 }

 

   3. 抽象類 (abstract class

 

    類是模具,有了類,就可以生產對象。

   

如果一個模具,計劃有10個功能,但最終仍然有2個功能沒有被實現,這個模具不能用於生產。

 

  同理,類也有類似的現象,有3個方法,實現了2個, 有1個還沒實現,但方法簽名已經計劃好了這個未實現的方法,必須用abstract來修飾,以通知系統本方法未實現,否則無法通過編譯,該方法爲抽象方法,擁有一個或者多個抽象方法的類,叫做抽象類。

 

抽象類是未完工的類,其不能用於生產實例!

 

創建實例       創建子類(繼承)     作爲引用變量數據類型

普通類         Yes             Yes                  Yes

Final類         Yes             No                  Yes

abstract類       no             Yes                  Yes

 

抽象類可以被繼承,而且渴望被繼承 (愚公移山的故事)

 

子類繼承父類,實現了父類的所有抽象方法,該子類可以脫掉抽象的帽子,成爲普通類,也稱可實例化類;否則,如果不實現父類抽象方法,則無論子類自身方法規模多麼龐大,也無法忽視內部有一個抽象方法的事實,子類是不完整的,這個不完整是父類帶來的,父類是子類的一部分,所以子類也還是抽象類,不能實例化。

 

抽象類語法識別注意點:

a. abstract void method3(){ };  //已經實現了,不能再說是抽象,這是矛盾的。

b. void method3( ) { };  // 請注意,空實現也是實現。

 

以上內容是抽象類的語法解釋。下面講解下抽象類的含義:

1) 被動抽象類

    因爲一個類的體內有抽象方法,該類不得不用抽象來修飾。

 

2) 主動抽象類

一個類所有方法都實現了,是可實例化類,其故意主動地聲明自己是抽象類。

一個類的作者爲了不讓使用者去創建這個類的實例,其故意申明此類爲抽象類。

比如: Animal , Shape, ValueObject…..

該類作者認爲這個類是一個抽象的概念,沒有創建實例的意義,該類需要被繼承,然後創建子類實例纔有意義。

 

任何一個類,無論是否有抽象方法,都可以abstract來修飾。

 

(例外:

不能用abstract來修飾已經用final修飾的類

     Abstract類渴望被繼承,而final拒絕繼承,兩者構成反義關係,不能同時存在,否則就構成了矛盾。

What will happen when you attempt to compile and run this code?

abstract class Base{

abstract public void myfunc() {};

public void another(){

System.out.println("Another method");

}

}

public class Abs extends Base{

public static void main(String argv[]){

Base b= new Abs(); //A

b. myfunc(); //B

}

public void myfunc(){

System.out.println("My Func");

}

public void amethod(){

myfunc();

}

}

[1 choice]

1) The code will compile and run, printing out the words "My Func"

2) The compiler will complain error at //A.

3) The compiler will complain error at //B.

4) The compiler will complain error at other position.

 

4. 接口 (interface)

 

   一個抽象類,所有的方法都是抽象的,所有方法的public, 我們把這樣的類叫做極度抽象類,是最乾癟的類。

   

public abstract class A {

public abstract void method1();

public abstract void method2();

public abstract void method3();

}

 

public interface A {

void method1();

void method2();

void method3();

}

   

極度抽象類可以縮寫爲接口。那麼,所有接口的方法都是public abstract.

 

 

類創建的過程

接口 (interface)  à  abstract class  à  可實例化類

 

創建實例       創建子類(繼承)     作爲引用變量數據類型

普通類         Yes             Yes                  Yes

Final類         Yes             No                  Yes

abstract類     no              Yes                  Yes

接口           no              yes                   yes

 

接口創建子類:

 1. Extends        繼承了接口,而得到結果還是接口。

      一個類沒有實現接口方法的計劃,而是想繼續增加接口方法,必須使用extends關鍵字來表示繼承。

 2.   implements    

      一個類如果有對接口方法做實現的計劃,必須使用implements關鍵字來繼承接口。

 

接口是一個特殊的類,一個類實現了接口,最終成爲可實例化類,那麼類必須包含接口中所定義的所有方法。

 

一個接口引用變量可以指向一個實現了這個接口的類對象,但只能調用這個對象中接口部分。

 

接口的用途:

 

  現實生活中,沒有血緣的對象之間往往有共同的行爲和動作,但每個對象的行爲和動作的具體內容是不一樣的,比如士兵, 每個士兵都是射擊,擒拿格鬥等行爲,但有的人是神槍手,而有的老是不及格,那麼也就是說大家都有這個動作,但動作的實現個人各自不同。

   以上是現實生活中的具體情況,爲了更好的模擬現實生活,語言必須演化,來滿足這個要求,極度抽象類在語法層面上滿足了這樣要求,被重視起來,並最終得到了一個新的名字,接口。

   

接口在某種程度上與多態有同樣的效果,能夠寫出可高度複用的代碼。

 

5. 訪問修飾符 (access modifier)

 

   現實生活中,一個人有很多屬性, 其不會把所有的屬性都告訴任何人,而是有選擇性對外說明,起到一個自我保護的作用,這也是算是一種“封裝”。

   根據軟件模擬現實的原則,語言設計者推出了訪問修飾符這個機制來實現封裝。

   

a. 從繼承角度談訪問修飾符

                       本類          同包子類         異包子類

Private                 yes            no             no

<package>            yes            yes             no

Protected              yes            yes             yes

Public                  yes            yes             yes

 

<package>修飾符只有本包內部類可見,外部類,即使是子類也看不到。

Protected 修飾符不僅本包內部可見,外包子類也可見。

 

b. 從引用角度談訪問修飾符

               本類   同包子類   同包非子類  異包子類   異包非子類

Private        yes     no          no         no        no

<package>   yes     yes          yes        no        no

Protected     yes     yes          yes        no        no

Public        yes      yes          yes        yes       yes

 

Assume that country is set for each class.

Given:

10. public class Money {

11. private String country, name;

12. public  String getCountry() { return country; }

13.}

and:

24. class Yen extends Money {

25. public String getCountry() { return super.country; }

26. }

27.

28. class Euro extends Money {

29. public String getCountry(String timeZone) {

30. return super.getCountry();

31. }

32. }

Which two are correct? (Choose two.)   答案:BE

A. Yen returns correct values.

B. Euro returns correct values.

C. An exception is thrown at runtime.

D. Yen and Euro both return correct values.

E. Compilation fails because of an error at line 25.

F. Compilation fails because of an error at line 30.

 

6. javabean

 

a. 廣義javabean的概念

   任何一個構成java應用程序的class文件,都叫javabean.

 

b. 狹義javabean概念

   

Ø 封裝 (encapsulation)

爲了保護一個類的屬性不被外界直接訪問,保護隱私,我們經常把屬性設置成私有,並配套兩個getter/setter方法對其進行匹配訪問。

 

   userName à  getUserName() , setUserName()

 

一個java類, 所有的屬性均爲私有,每個屬性配套一對getter/setter方法進行屬性的訪問,同時該類還有一個無參構造方法,符合以上條件書寫的類,被稱爲javabean.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章