1. 程式人生 > >java中的繼承和多型以及過載和重寫

java中的繼承和多型以及過載和重寫

繼承(inheritance)

       簡單的說,繼承就是在一個現有型別的基礎上,通過增加新的方法或者重定義已有方法(下面會講到,這種方式叫重寫)的方式,產生一個新的型別。繼承是面向物件的三個基本特徵--封裝、繼承、多型的其中之一,我們在使用JAVA時編寫的每一個類都是在繼承,因為在JAVA語言中,java.lang.Object類是所有類最根本的基類(或者叫父類、超類),如果我們新定義的一個類沒有明確地指定繼承自哪個基類,那麼JAVA就會預設為它是繼承自Object類的。

我們可以把JAVA中的類分為以下三種:

類:使用class定義且不含有抽象方法的類。
抽象類:使用abstract class定義的類,它可以含有,也可以不含有抽象方法。
介面:使用interface定義的類。

在這三種類型之間存在下面的繼承規律:

類可以繼承(extends)類,可以繼承(extends)抽象類,可以繼承(implements)介面。
抽象類可以繼承(extends)類,可以繼承(extends)抽象類,可以繼承(implements)介面。
介面只能繼承(extends)介面。

請注意上面三條規律中每種繼承情況下使用的不同的關鍵字extends和implements,它們是不可以隨意替換的。大家知道,一個普通類繼承一個介面後,必須實現這個介面中定義的所有方法,否則就只能被定義為抽象類。我在這裡之所以沒有對implements關鍵字使用“實現”這種說法是因為從概念上來說它也是表示一種繼承關係,而且對於抽象類implements介面的情況下,它並不是一定要實現這個介面定義的任何方法,因此使用繼承的說法更為合理一些。

以上三條規律同時遵守下面這些約束:

類和抽象類都只能最多繼承一個類,或者最多繼承一個抽象類,並且這兩種情況是互斥的,也就是說它們要麼繼承一個類,要麼繼承一個抽象類。
類、抽象類和介面在繼承介面時,不受數量的約束,理論上可以繼承無限多個介面。當然,對於類來說,它必須實現它所繼承的所有介面中定義的全部方法。
抽象類繼承抽象類,或者實現介面時,可以部分、全部或者完全不實現父類抽象類的抽象(abstract)方法,或者父類介面中定義的介面。
類繼承抽象類,或者實現介面時,必須全部實現父類抽象類的全部抽象(abstract)方法,或者父類介面中定義的全部介面。

繼承給我們的程式設計帶來的好處就是對原有類的複用(重用)。就像模組的複用一樣,類的複用可以提高我們的開發效率,實際上,模組的複用是大量類的複用疊加後的效果。除了繼承之外,我們還可以使用組合的方式來複用類。所謂組合就是把原有類定義為新類的一個屬性,通過在新類中呼叫原有類的方法來實現複用。如果新定義的型別與原有型別之間不存在被包含的關係,也就是說,從抽象概念上來講,新定義型別所代表的事物並不是原有型別所代表事物的一種,比如黃種人是人類的一種,它們之間存在包含與被包含的關係,那麼這時組合就是實現複用更好的選擇。

多型(Polymorphism)

多型是又一個重要的基本概念,上面說到了,它是面向物件的三個基本特徵之一。究竟什麼是多型呢?我們先看看下面的例子,來幫助理解:

//汽車介面 
interface Car { 
  // 汽車名稱 
  String getName(); 
  
  // 獲得汽車售價 
  int getPrice(); 
} 
  
// 寶馬 
class BMW implements Car { 
  public String getName() { 
    return "BMW"; 
  } 
  
  public int getPrice() { 
    return 300000; 
  } 
} 
  
// 奇瑞QQ 
class CheryQQ implements Car { 
  public String getName() { 
    return "CheryQQ"; 
  } 
  
  public int getPrice() { 
    return 20000; 
  } 
} 
  
// 汽車出售店 
public class CarShop { 
  // 售車收入 
  private int money = 0; 
  
  // 賣出一部車 
  public void sellCar(Car car) { 
    System.out.println("車型:" + car.getName() + " 單價:" + car.getPrice()); 
    // 增加賣出車售價的收入 
    money += car.getPrice(); 
  } 
  
  // 售車總收入 
  public int getMoney() { 
    return money; 
  } 
  
  public static void main(String[] args) { 
    CarShop aShop = new CarShop(); 
    // 賣出一輛寶馬 
    aShop.sellCar(new BMW()); 
    // 賣出一輛奇瑞QQ 
    aShop.sellCar(new CheryQQ()); 
    System.out.println("總收入:" + aShop.getMoney()); 
  } 
} 
?

執行結果:

車型:BMW  單價:300000
車型:CheryQQ  單價:20000
總收入:320000

繼承是多型得以實現的基礎。從字面上理解,多型就是一種型別(都是Car型別)表現出多種狀態(寶馬汽車的名稱是BMW,售價是300000;奇瑞汽車的名稱是CheryQQ,售價是2000)。將一個方法呼叫同這個方法所屬的主體(也就是物件或類)關聯起來叫做繫結,分前期繫結和後期繫結兩種。下面解釋一下它們的定義:

前期繫結:在程式執行之前進行繫結,由編譯器和連線程式實現,又叫做靜態繫結。比如static方法和final方法,注意,這裡也包括private方法,因為它是隱式final的。
後期繫結:在執行時根據物件的型別進行繫結,由方法呼叫機制實現,因此又叫做動態繫結,或者執行時繫結。除了前期繫結外的所有方法都屬於後期繫結。

多型就是在後期繫結這種機制上實現的。多型給我們帶來的好處是消除了類之間的耦合關係,使程式更容易擴充套件。比如在上例中,新增加一種型別汽車的銷售,只需要讓新定義的類繼承Car類並實現它的所有方法,而無需對原有程式碼做任何修改,CarShop類的sellCar(Car car)方法就可以處理新的車型了。

Java多型特性———過載(overloading)和重寫(overriding)

Java過載:

  • 在同一個類中
  • 方法具有相同的名字,相同或不同的返回值,但引數不同的多個方法(引數個數或引數型別)
  1. publicclass MethoDemo{  
  2.     publicstaticvoid main(String args[]){  
  3.         int one = add(10,20) ;      // 呼叫整型的加法操作
  4.         float two = add(10.3f,13.3f) ;  // 呼叫浮點數的加法操作
  5.         int three = add(10,20,30) ; // 呼叫有三個引數的加法操作
  6.         System.out.println("add(int x,int y)的計算結果:" + one) ;  
  7.         System.out.println("add(float x,float y)的計算結果:" + two) ;  
  8.         System.out.println("add(int x,int y,int z)的計算結果:" + three) ;  
  9.     }  
  10.     // 定義方法,完成兩個數字的相加操作,方法返回一個int型資料
  11.     publicstaticint add(int x,int y){  
  12.         int temp = 0 ;          // 方法中的引數,是區域性變數
  13.         temp = x + y ;          // 執行加法計算
  14.         return temp ;           // 返回計算結果
  15.     }  
  16.     publicstaticint add(int x,int y,int z){  
  17.         int temp = 0 ;          // 方法中的引數,是區域性變數
  18.         temp = x + y + z ;          // 執行加法計算
  19.         return temp ;           // 返回計算結果
  20.     }  
  21.     // 定義方法,完成兩個數字的相加操作,方法的返回值是一個float型資料
  22.     publicstaticfloat add(float x,float y){  
  23.         float temp = 0 ;        // 方法中的引數,是區域性變數
  24.         temp = x + y ;          // 執行加法操作
  25.         return temp ;           // 返回計算結果
  26.     }  
  27. };  
輸出結果:

add(int x,int y)的計算結果:30

add(float x,float y)的計算結果:60

add(int x,int y,int z)的計算結果:23.6

Java覆寫:

  • 子類覆寫父類的方法,在不同的類
  • 重寫方法必須和被重寫方法具有相同方法名稱、引數列表和返回型別
  • 重寫方法不能使用比被重寫方法更嚴格的訪問許可權
  1. class Person{       // 定義父類
  2.     void print(){   // 預設的訪問許可權
  3.         System.out.println("Person --> void print()。") ;  
  4.     }  
  5. };  
  6. class Student extends Person{   // 定義繼承關係
  7.     publicvoid print(){  
  8.         System.out.println("Student --> void print()。") ;  
  9.     }  
  10. };  
  11. publicclass OverrideDemo{  
  12.     publicstaticvoid main(String args[]){  
  13.         Student s = new Student() ;  
  14.         s.print() ;  
  15.     }  
  16. };  
輸出結果:

Student --> void print()。

小結:

java的三大特性:封裝,繼承,多型.而方法的過載和覆寫正是多型的體現.