一、方法重載
如果子類中的方法與它的超類中的方法有相同的方法名,則稱子類中的方法重載超類中的方法,特別是當(dāng)超類和子類中的方法名和參數(shù)類型都相同時(shí),在子類中調(diào)用該方法時(shí),超類中的方法會被隱藏??紤]下面程序:
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.運(yùn)行結(jié)果:k: 3
子類B中的show()重載了超類A中的show(),從子類中調(diào)用重載方法時(shí)(41行),它總是引用子類定義的方法(28-31行),超類中的show()方法(11-14行)被隱藏。當(dāng)然如果希望訪問被重載的超類方法,可以用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 } 如果用這段代碼替換上面的版本,運(yùn)行結(jié)果會變?yōu)椋?/p>
i and j: 1 2k: 3
super.show()調(diào)用了被隱藏的超類的方法。
注意,當(dāng)子類和超類中僅僅是方法名相同而參數(shù)類型不同時(shí),利用子類調(diào)用該方法時(shí)系統(tǒng)會根據(jù)輸入的參數(shù)類型來判斷到底使用哪一個(gè)版本。
二、動態(tài)方法調(diào)度
上面的例子解釋了何為方法重載。方法重載的真正意義在于它構(gòu)成了Java一個(gè)最強(qiáng)大的概念的基礎(chǔ):動態(tài)方法調(diào)度。動態(tài)方法調(diào)度是一種在程序運(yùn)行時(shí)而不是編譯時(shí)調(diào)用重載方法的機(jī)制,它是實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)性的基礎(chǔ)。
考慮下面程序:
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; // 聲明一個(gè)對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
程序創(chuàng)建了一個(gè)名為A的超類以及它的兩個(gè)子類B和C。子類B和C重載A中定義的callme( )方法。main( )主函數(shù)中,聲明了A、B和C類的對象。而且,一個(gè)A類型的引用r也被聲明。就像輸出所顯示的,所執(zhí)行的callme( )版本由調(diào)用時(shí)引用對象的類型決定。
由上述例子我們可以看到,重載方法允許Java支持運(yùn)行時(shí)多態(tài)性,就是在程序運(yùn)行的時(shí)候選擇使用哪一個(gè)版本的方法,從而實(shí)現(xiàn)“一個(gè)接口,多個(gè)方法”。超類提供子類可以直接運(yùn)用的所有元素。多態(tài)也定義了這些派生類必須自己實(shí)現(xiàn)的方法。這允許子類在加強(qiáng)一致接口的同時(shí),靈活的定義它們自己的方法。
三、應(yīng)用方法重載
下面的程序創(chuàng)建了一個(gè)名為Figure的超類,它存儲不同二維對象的大小。它還定義了一個(gè)方法area( ),該方法計(jì)算對象的面積。程序從Figure派生了兩個(gè)子類。第一個(gè)是Rectangle,第二個(gè)是Triangle。每個(gè)子類重載area( )方法,它們分別返回一個(gè)矩形和一個(gè)三角形的面積。
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
這種情況下, 如果一個(gè)對象是從Figure派生, 那么它的面積可以由調(diào)用area( )來獲得。無論用到哪種圖形的類型,該操作的接口是相同的。
四、使用抽象類
回看前面的例子中,超類Figure中,area( )的定義僅是一個(gè)占位符,它不會計(jì)算和顯示任何類型對象的面積。也就是說,有時(shí)候我們希望定義一個(gè)超類,但是該超類只給定一種類的結(jié)構(gòu)但是不提供方法的實(shí)現(xiàn),而繼承超類的子類共享這種結(jié)構(gòu),具體的實(shí)現(xiàn)由每個(gè)子類自己填寫。
還是考慮上面的例子,對于Triangle類,如果它自己不定義area(),那么它將變得毫無意義。所以這種情況下,必須確保子類真正重載了所有必須的方法。Java對于這個(gè)問題的解決使用的是抽象方法(abstract method).通過abstract 修飾符指定某些方法必須由子類實(shí)現(xiàn),你不去實(shí)現(xiàn)就不讓你運(yùn)行,這樣子類就必須重載它們,而不能簡單使用超類中定義的版本。
考慮下面的程序:
1 // A Simple demonstration of abstract. 2 abstract class A 3 { 4 abstract void callme();//聲明抽象方法,不具體實(shí)現(xiàn),交給子類實(shí)現(xiàn) 5 6 // 用一個(gè)抽象類去實(shí)例化一個(gè)對象是不允許的,但在類里面實(shí)現(xiàn)一個(gè)具體方法還是允許的 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() //實(shí)現(xiàn)超類的抽象方法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.
由上面程序總結(jié)出使用抽象類要注意:
- 聲明一個(gè)抽象方法的通用形式:abstract type name(parameter-list)(第4行)
- 一個(gè)類只要含有一個(gè)或多個(gè)抽象類方法,它就變成了抽象類,就必須聲明為抽象類(第二行所示)
- 盡管抽象類不能用來實(shí)例化(即不能用來建立一個(gè)具體的對象,語句A a = new A()就是非法的),但是它們可以用來創(chuàng)建對象引用(如25行所示)
- 抽象類實(shí)例化抽象類不可以,但抽象類可以自己實(shí)現(xiàn)任意數(shù)量的具體方法(如7-10行實(shí)現(xiàn)了一個(gè)具體方法)
- 所有子類都必須具體實(shí)現(xiàn)超類中的抽象方法或者改子類自己聲明為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); // 非法的,因?yàn)槌橄箢愂遣荒軌騽?chuàng)建對象的52 Rectangle r = new Rectangle(9, 5); 53 Triangle t = new Triangle(10, 8); 54 Figure figref; // 僅僅聲明了一個(gè)指向Figure類的引用,是不會創(chuàng)建具體對象的,所以語句合法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的一個(gè)引用,意思是說它可以用來引用任何從Figure派生的對象。
新聞熱點(diǎn)
疑難解答
圖片精選