一、方法重載
如果子類中的方法與它的超類中的方法有相同的方法名,則稱子類中的方法重載超類中的方法,特別是當超類和子類中的方法名和參數類型都相同時,在子類中調用該方法時,超類中的方法會被隱藏。考慮下面程序:
1 class A 2 { 3 int i, j; 4 A(int a, int b) 5 { 6 i = a; 7 j = b; 8 } 9 10 // display i and j 11 void show() 12 { 13 System.out.運行結果:k: 3
子類B中的show()重載了超類A中的show(),從子類中調用重載方法時(41行),它總是引用子類定義的方法(28-31行),超類中的show()方法(11-14行)被隱藏。當然如果希望訪問被重載的超類方法,可以用super,如下:
1 class B extends A 2 { 3 int k; 4 5 B(int a, int b, int c) 6 { 7 super(a, b); 8 k = c; 9 } 10 void show() 11 { 12 super.show(); // this calls A's show() 13 System.out.println("k: " + k); 14 } 15 }如果用這段代碼替換上面的版本,運行結果會變為:
i and j: 1 2k: 3
super.show()調用了被隱藏的超類的方法。
注意,當子類和超類中僅僅是方法名相同而參數類型不同時,利用子類調用該方法時系統會根據輸入的參數類型來判斷到底使用哪一個版本。
二、動態方法調度
上面的例子解釋了何為方法重載。方法重載的真正意義在于它構成了Java一個最強大的概念的基礎:動態方法調度。動態方法調度是一種在程序運行時而不是編譯時調用重載方法的機制,它是實現運行時多態性的基礎。
考慮下面程序:
1 // Dynamic Method Dispatch 2 class A 3 { 4 void callme() 5 { 6 System.out.println("Inside A's callme method"); 7 } 8 } 9 10 class B extends A 11 { 12 // override callme() 13 void callme() 14 { 15 System.out.println("Inside B's callme method"); 16 } 17 } 18 19 class C extends A 20 { 21 // override callme() 22 void callme() 23 { 24 System.out.println("Inside C's callme method"); 25 } 26 } 27 28 public class myJavaTest 29 { 30 public static void main(String args[]) 31 { 32 A a = new A(); // object of type A 33 B b = new B(); // object of type B 34 C c = new C(); // object of type C 35 A r; // 聲明一個對A的引用 r 36 37 r = a; // 引用r指向A的對象38 r.callme(); // calls A's version of callme39 40 r = b; // 引用r指向B的對象41 r.callme(); // calls B's version of callme42 r = c; // 引用r指向C的對象 43 r.callme(); // calls C's version of callme44 } 45 }輸出如下:
Inside A's callme methodInside B's callme methodInside C's callme method
程序創建了一個名為A的超類以及它的兩個子類B和C。子類B和C重載A中定義的callme( )方法。main( )主函數中,聲明了A、B和C類的對象。而且,一個A類型的引用r也被聲明。就像輸出所顯示的,所執行的callme( )版本由調用時引用對象的類型決定。
由上述例子我們可以看到,重載方法允許Java支持運行時多態性,就是在程序運行的時候選擇使用哪一個版本的方法,從而實現“一個接口,多個方法”。超類提供子類可以直接運用的所有元素。多態也定義了這些派生類必須自己實現的方法。這允許子類在加強一致接口的同時,靈活的定義它們自己的方法。
三、應用方法重載
下面的程序創建了一個名為Figure的超類,它存儲不同二維對象的大小。它還定義了一個方法area( ),該方法計算對象的面積。程序從Figure派生了兩個子類。第一個是Rectangle,第二個是Triangle。每個子類重載area( )方法,它們分別返回一個矩形和一個三角形的面積。
1 class Figure 2 { 3 double dim1; 4 double dim2; 5 6 Figure(double a, double b) 7 { 8 dim1 = a; 9 dim2 = b; 10 } 11 12 double area() 13 { 14 System.out.println("Area for Figure is undefined."); 15 return 0; 16 } 17 } 18 19 class Rectangle extends Figure 20 { 21 Rectangle(double a, double b) 22 { 23 super(a, b); 24 } 25 26 // override area for rectangle 27 double area() 28 { 29 System.out.println("Inside Area for Rectangle."); 30 return dim1 * dim2; 31 } 32 } 33 34 class Triangle extends Figure 35 { 36 Triangle(double a, double b) 37 { 38 super(a, b); 39 } 40 41 // override area for right triangle 42 double area() 43 { 44 System.out.println("Inside Area for Triangle."); 45 return dim1 * dim2 / 2; 46 } 47 } 48 49 public class myJavaTest 50 { 51 public static void main(String args[]) 52 { 53 Figure f = new Figure(10, 10); 54 Rectangle r = new Rectangle(9, 5); 55 Triangle t = new Triangle(10, 8); 56 57 Figure figref; 58 59 figref = r; 60 System.out.println("Area is " + figref.area()); 61 62 figref = t; 63 System.out.println("Area is " + figref.area()); 64 65 figref = f; 66 System.out.println("Area is " + figref.area()); 67 68 }69 }輸出:
Inside Area for Rectangle.Area is 45.0Inside Area for Triangle.Area is 40.0Area for Figure is undefined.Area is 0.0
這種情況下, 如果一個對象是從Figure派生, 那么它的面積可以由調用area( )來獲得。無論用到哪種圖形的類型,該操作的接口是相同的。
四、使用抽象類
回看前面的例子中,超類Figure中,area( )的定義僅是一個占位符,它不會計算和顯示任何類型對象的面積。也就是說,有時候我們希望定義一個超類,但是該超類只給定一種類的結構但是不提供方法的實現,而繼承超類的子類共享這種結構,具體的實現由每個子類自己填寫。
還是考慮上面的例子,對于Triangle類,如果它自己不定義area(),那么它將變得毫無意義。所以這種情況下,必須確保子類真正重載了所有必須的方法。Java對于這個問題的解決使用的是抽象方法(abstract method).通過abstract 修飾符指定某些方法必須由子類實現,你不去實現就不讓你運行,這樣子類就必須重載它們,而不能簡單使用超類中定義的版本。
考慮下面的程序:
1 // A Simple demonstration of abstract. 2 abstract class A 3 { 4 abstract void callme();//聲明抽象方法,不具體實現,交給子類實現 5 6 // 用一個抽象類去實例化一個對象是不允許的,但在類里面實現一個具體方法還是允許的 7 void callmetoo() 8 { 9 System.out.println("This is a concrete method."); 10 } 11 } 12 13 class B extends A 14 { 15 void callme() //實現超類的抽象方法16 { 17 System.out.println("B's implementation of callme."); 18 } 19 } 20 21 public class myJavaTest 22 { 23 public static void main(String args[]) 24 { 25 A a; 26 B b = new B(); 27 a = b;28 a.callme(); 29 a.callmetoo(); 30 } 31 }輸出:
B's implementation of callme.This is a concrete method.
由上面程序總結出使用抽象類要注意:
- 聲明一個抽象方法的通用形式:abstract type name(parameter-list)(第4行)
- 一個類只要含有一個或多個抽象類方法,它就變成了抽象類,就必須聲明為抽象類(第二行所示)
- 盡管抽象類不能用來實例化(即不能用來建立一個具體的對象,語句A a = new A()就是非法的),但是它們可以用來創建對象引用(如25行所示)
- 抽象類實例化抽象類不可以,但抽象類可以自己實現任意數量的具體方法(如7-10行實現了一個具體方法)
- 所有子類都必須具體實現超類中的抽象方法或者改子類自己聲明為abstract
下面用抽象類改善前面的Figure類:
1 // Using abstract methods and classes. 2 abstract class Figure 3 { 4 double dim1; 5 double dim2; 6 7 Figure(double a, double b) 8 { 9 dim1 = a; 10 dim2 = b; 11 } 12 13 // area is now an abstract method 14 abstract double area(); 15 } 16 17 class Rectangle extends Figure 18 { 19 Rectangle(double a, double b) 20 { 21 super(a, b); 22 } 23 24 // override area for rectangle 25 double area() 26 { 27 System.out.println("Inside Area for Rectangle."); 28 return dim1 * dim2; 29 } 30 } 31 32 class Triangle extends Figure 33 { 34 Triangle(double a, double b) 35 { 36 super(a, b); 37 } 38 39 // override area for right triangle 40 double area() 41 { 42 System.out.println("Inside Area for Triangle.");43 return dim1 * dim2 / 2; 44 } 45 } 46 47 public class myJavaTest 48 { 49 public static void main(String args[]) 50 { 51 // Figure f = new Figure(10, 10); // 非法的,因為抽象類是不能夠創建對象的52 Rectangle r = new Rectangle(9, 5); 53 Triangle t = new Triangle(10, 8); 54 Figure figref; // 僅僅聲明了一個指向Figure類的引用,是不會創建具體對象的,所以語句合法55 56 figref = r; 57 System.out.println("Area is " + figref.area()); 58 59 figref = t; 60 System.out.println("Area is " + figref.area()); 61 } 62 }56行變量figref聲明成Figure的一個引用,意思是說它可以用來引用任何從Figure派生的對象。
新聞熱點
疑難解答