Java編程—在測試中考慮多態(tài)
面向?qū)ο缶幊逃腥筇匦裕悍庋b、繼承、多態(tài)。
封裝隱藏了類的內(nèi)部實現(xiàn)機制,可以在不影響使用的情況下改變類的內(nèi)部結(jié)構(gòu),同時也保護了數(shù)據(jù)。對外界而已它的內(nèi)部細節(jié)是隱藏的,暴露給外界的只是它的訪問方法。
繼承是為了重用父類代碼。兩個類若存在IS-A的關(guān)系就可以使用繼承。,同時繼承也為實現(xiàn)多態(tài)做了鋪墊。那么什么是多態(tài)呢?多態(tài)的實現(xiàn)機制又是什么?請看我一一為你揭開:
所謂多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調(diào)用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量倒底會指向哪個類的實例對象,該引用變量發(fā)出的方法調(diào)用到底是哪個類中實現(xiàn)的方法,必須在由程序運行期間才能決定。因為在程序運行時才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實現(xiàn)上,從而導(dǎo)致該引用調(diào)用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態(tài),這就是多態(tài)性。練習(xí)(1):創(chuàng)建一個Cycle類,它具有子類Unicycle,Bycycle,Tricycle.演示每一個類型的實例都可以經(jīng)由ride()方法向上轉(zhuǎn)型為Cycle.
向上轉(zhuǎn)型就是允許將多種從同一基類的導(dǎo)出類看成同一類型。
多態(tài)方法調(diào)用就是允許一種類型表現(xiàn)出與其他相似類型之間的區(qū)別,只要他們是從同一基類導(dǎo)出而來的。這種區(qū)別由各個導(dǎo)出類型方法的具體不同實現(xiàn)而表現(xiàn)出來的,雖然這些方法都是由基類調(diào)用的。
public class Test1 { public static void main(String[] args){ Unicycle unicycle = new Unicycle("Unicycle"); Bicycle bicycle = new Bicycle("Bicycle"); Tricycle tricycle = new Tricycle("Tricycle"); Cycle.ride(unicycle); Cycle.ride(bicycle); Cycle.ride(tricycle); } } class Cycle{ private String name; public Cycle(String str){ name = str; } public static void ride(Cycle c){ System.out.println(c.name + "is riding"); } } class Unicycle extends Cycle{ private String name; public Unicycle(String str) { super(str); name = str; } } class Bicycle extends Cycle{ private String name; public Bicycle(String str) { super(str); name = str; } } class Tricycle extends Cycle { private String name; public Tricycle(String str) { super(str); name = str; } }
輸出:
Unicycleis riding
Bicycleis riding
Tricycleis riding
在以上示例中,三種子類能被視作Cycle傳入到方法ride()中就是向上轉(zhuǎn)型。
但向上轉(zhuǎn)型只是看成,而不是強制轉(zhuǎn)換,所以最后方法調(diào)用的結(jié)果不同,這就是多態(tài)。
多態(tài)又稱之為動態(tài)綁定。什么是動態(tài)綁定?
與動態(tài)綁定相反的是靜態(tài)綁定。c語言所有方法都是默認靜態(tài)綁定。靜態(tài)綁定也稱為前期綁定,就是在程序運行前就綁定完成。也就是說,代碼寫了什么樣,就是什么樣。
而動態(tài)綁定是直到運行時才去決定該方法調(diào)用該綁定哪個實體。
java中的所有static和final方法都是靜態(tài)綁定,其他的所有方法都是動態(tài)綁定。
練習(xí)(2):在幾何圖形示例中添加@Override注解。
練習(xí)(3):在基類Shape.java中添加一個新方法,用于打印一條消息,但導(dǎo)出類中不要覆蓋這個方法。請解釋發(fā)生了什么。現(xiàn)在,在其中一個導(dǎo)出類中覆蓋該方法,而在其他的導(dǎo)出類中不予覆蓋,觀察又有什么發(fā)生。最后,在所有的導(dǎo)出類中覆蓋這個方法。
練習(xí)(4):向Shapes.java中添加一個新的Shape類型,并在main()方法中驗證:多態(tài)對新類型的作用是否與在舊類型中的一樣。
以上三個練習(xí)在一份示例中完成。
public class Test234 { private static RandonShapeGenerator gen = new RandonShapeGenerator(); public static void main(String[] args){ Shape[] shapes = new Shape[9]; for (int i = 0; i < shapes.length; i++) { shapes[i] = gen.next(); } for (Shape s : shapes) { s.draw(); s.newMethod();//每個子類都調(diào)用了一次添加的新方法, // 因為子類繼承父類自然把所有方法都繼承過去了,只不過沒有顯示出來, // 其實是隱式的存在的,子類調(diào)用的其實是繼承自父類的沒有重寫的方法, // 看起來像是調(diào)用了父類的方法 } Shape s = new Recf();//這里是聲明了一個Shape類型的引用,但實際的對象還是Recf. s.draw();//輸出的是Recf類重寫的方法,證明多態(tài)對新類的作用于在舊類中是一樣的 } } class Shape{//基類 public void draw(){} public void erase(){} public void newMethod(){ System.out.println("new method");//添加的新方法 } } class Circle extends Shape{ @Override//添加注解,一般IDE可以自動添加 public void draw() { System.out.println("draw circle"); } @Override public void erase() { System.out.println("erase circle"); } } class Square extends Shape{ @Override public void draw() { System.out.println("draw Square"); } @Override public void erase() { System.out.println("erase Square"); } @Override public void newMethod() { System.out.println("Square new method"); //重寫后該類輸出內(nèi)容就發(fā)生改變,沒有重寫時該類的該方法與父類運行結(jié)果相同 //無論重寫與否,其實調(diào)用的都是自身的方法 //只是沒有重寫時方法調(diào)用結(jié)果與父類的相同 } } class Triangle extends Shape{ @Override public void draw() { System.out.println("draw Triangle"); } @Override public void erase() { System.out.println("erase Triangle"); } } class Recf extends Shape{//新添加的方法 @Override public void draw() { System.out.println("recf draw"); } @Override public void erase() { System.out.println("recf erase"); } } class RandonShapeGenerator{//是一種工廠,用以隨機獲取一種Shape的子類 private Random rand = new Random(100); public Shape next(){ switch (rand.nextInt(3)){ default: case 0:return new Circle(); case 1:return new Square(); case 2:return new Triangle(); } } }
練習(xí)(5):以練習(xí)1為基礎(chǔ),才Cycle中添加wheels()方法,它將返回輪子的數(shù)量。修改ride()方法,讓它調(diào)用wheels()方法,并驗證多態(tài)起作用了。
在練習(xí)(1)的代碼中給基類添加
public void wheels(){ System.out.println("輪子數(shù)量是" + num); }
然后在main中:
unicycle.wheels(); bicycle.wheels(); tricycle.wheels();
最后輸出結(jié)果都順利輸出了方法中的語句,證明多態(tài)確實起作用了。
練習(xí)(6):修改Music3.java,是what()方法成為根Object的toString()方法。試用System.out.pringtln()方法打印Instrument對象(不用向上轉(zhuǎn)型).
練習(xí)(7):向Music3.java添加一個新的類型Instrument,并驗證多態(tài)性是否作用于所添加的新類型.
練習(xí)(8):修改Music3.java,使其可以向Shapes.java中的方式那樣隨機創(chuàng)建Instrument對象。
三個練習(xí)將在一份代碼完成。
public class Test678 { public static void main(String[] args){ Instrument[] orchestar = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwing() }; tuneAll(orchestar); newInstrument ni = new newInstrument(); ni.play(Note.B_FLAT);//驗證多態(tài)性是否適用于所添加的新類型,答案是確實適用。 } public static void tune(Instrument instrument){ instrument.play(Note.MIDDLE_C);//無論傳進聲明子類,都 MIDDLE_C } public static void tuneAll(Instrument[] e){ for (Instrument i : e) { tune(i); System.out.println(i.toString()); } } } class RandomInsFactory{//工廠類,用于隨機生成一個Instrument的子類 private Random ran = new Random(47); public Instrument next(){ switch (ran.nextInt(5)){ default: case 0:return new Wind(); case 1:return new Percussion(); case 2:return new Stringed(); case 3:return new Brass(); case 4:return new Woodwing(); case 5:return new newInstrument(); } } } enum Note{//枚舉類,存放了哪些音樂 MIDDLE_C,C_HARPE,B_FLAT; } class Instrument { void play(Note note){ System.out.println("Instrument.play() : " + note); } String what(){ return "Instrument"; } void adjust(){ System.out.println("adjusting Instrument"); } @Override public String toString() { // /添加一個toString方法,調(diào)用當(dāng)前what方法, // 子類會自動繼承該方法并分別返回給自what()里的內(nèi)容 return what(); } } class Wind extends Instrument{ @Override void play(Note note) { System.out.println("Wind.play() : " + note); } @Override String what() { return "Wind"; } @Override void adjust() { System.out.println("adjusting Wind"); } } class Percussion extends Instrument{ @Override void play(Note note) { System.out.println("Percussion.play() : " + note); } @Override String what() { return "Percussion"; } @Override void adjust() { System.out.println("adjusting Percussion"); } } class Stringed extends Instrument{ @Override void play(Note note) { System.out.println("Stringed.play() : " + note); } @Override String what() { return "Stringed"; } @Override void adjust() { System.out.println("adjusting Stringed"); } } class Brass extends Wind{//繼承自Wind @Override void play(Note note) { System.out.println("Brass.play() : " + note); } @Override void adjust() { System.out.println("adjusting Brass"); } } class Woodwing extends Wind{ @Override void play(Note note) { System.out.println("Woodwing.play() : " + note); } @Override String what() { return "Woodwing"; } } class newInstrument extends Instrument{//新添加的類型 @Override void play(Note note) { System.out.println("newIns.play()" + note); } }
練習(xí)(9):創(chuàng)建Rodent(嚙齒動物):Mouse(老鼠),Gerbil(鼴鼠),Hamster(大頰鼠),等等這樣一個的繼承層次結(jié)構(gòu)。在基類中,提供對所有的Rodent都通用的方法,在導(dǎo)出類中,根據(jù)特定的Rodent類型覆蓋這些方法,以便觀察它們執(zhí)行不同的行為。創(chuàng)建一個Rodent數(shù)組,填充不同的Rodent類型,然后調(diào)用基類方法,觀察發(fā)生了什么情況。
這跟前面Instrument的例子相似,在Instrument中有what()這個對所有Instrument都通用的方法,而在每個子類中我們都覆蓋了這個方法并賦予了不同的行為,最終在main中創(chuàng)建了Instrument數(shù)組,調(diào)用了基類方法,最后得到的結(jié)果是不同類調(diào)用基類方法得到的輸出是該類重寫后的結(jié)果。不再重復(fù)。
練習(xí)(10):創(chuàng)建一個包含兩個方法的基類。在第一個方法中可以調(diào)用第二個方法。然后產(chǎn)生一個繼承自該基類的導(dǎo)出類,且覆蓋基類中的第二個方法。為該導(dǎo)出類創(chuàng)建一個對象,將它向上轉(zhuǎn)型為基類并調(diào)用第一個方法,解釋發(fā)生的情況。
public class Test10 { public static void main(String[] args){ jilei j = new daochulei();//創(chuàng)建導(dǎo)出類的對象并轉(zhuǎn)型為基類 j.first();//調(diào)用第一個方法 //結(jié)果輸出daochulei is running //原因,就像前面提過的,導(dǎo)出類繼承了基類的所有東西,沒有重寫的方法隱藏了起來 //其實在daochulei中還隱士的有void first()這個方法里調(diào)用了自身重寫的second() //當(dāng)daochulei調(diào)用first()方法后,它就調(diào)用了自身重寫的second()方法。 //導(dǎo)出類調(diào)用基類方法其實不是真的調(diào)用,而是調(diào)用自身繼承自基類的方法, // 只不過這個方法沒重寫時,內(nèi)部形式與基類相同 } } class jilei{ void first(){//調(diào)用第二個方法 second(); } void second(){ System.out.println("first is running"); } } class daochulei extends jilei{ @Override void second() { System.out.println("daochulei is running"); } }
練習(xí)(11)跳過
練習(xí)(12):修改練習(xí)(9),使其能夠演示基類和導(dǎo)出類的初始化順序。然后向基類和導(dǎo)出類中添加成員對象,并說明構(gòu)建期間初始化發(fā)生的順序。
public class Test912 { public static void main(String[] args){ new Hamster(); } } class Rodent{ public Rodent(){ shanghai = 100; System.out.println("Rodent"); } private int shanghai; public void bite(){ System.out.println("造成傷害" +shanghai + "點" ); } } class Mouse extends Rodent{ private int sh; public Mouse(){ sh = 1000; System.out.println("Mouse"); } @Override public void bite() { System.out.println("造成傷害" +sh + "點" ); } } class Gerbil extends Mouse{ private int shang; public Gerbil(){ shang = 2000; System.out.println("Gerbil"); } @Override public void bite() { System.out.println("造成傷害" +shang + "點" ); } } class Hamster extends Gerbil{ private Mouse mouse = new Mouse();//成員對象 //該類初始化輸出結(jié)果 //Rodent // Mouse // Gerbil // Rodent // Mouse // Hamster //可以分析出,初始化時先調(diào)用基類的構(gòu)造方法, // 然后初始化成員變量,因為其中有Mouse這個成員對象,所有對Mouse進行初始化, // 完成后再調(diào)用自身的構(gòu)造方法 private int hai; public Hamster(){ hai = 3000; System.out.println("Hamster"); } @Override public void bite() { System.out.println("造成傷害" + hai + "點" ); } }
總結(jié)
以上就是本文關(guān)于Java編程—在測試中考慮多態(tài)的全部內(nèi)容,希望對大家有所幫助。歡迎參閱:Java面向?qū)ο缶幊蹋ǚ庋b/繼承/多態(tài))實例解析、Java實現(xiàn)微信公眾平臺朋友圈分享功能詳細代碼、Java編程BigDecimal用法實例分享等,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
上一篇:Java編程將漢字轉(zhuǎn)Unicode碼代碼示例
欄 目:Java編程
下一篇:java編程隊列數(shù)據(jù)結(jié)構(gòu)代碼示例
本文標題:Java編程—在測試中考慮多態(tài)
本文地址:http://mengdiqiu.com.cn/a1/Javabiancheng/8427.html
您可能感興趣的文章
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10Java Socket編程(三) 服務(wù)器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java經(jīng)驗點滴:處理沒有被捕獲的異常
- 01-10Java Socket編程(四) 重復(fù)和并發(fā)服務(wù)器
- 01-10Java中的浮點數(shù)分析
- 01-10面向?qū)ο缶幊?Java中的抽象數(shù)據(jù)類型


閱讀排行
本欄相關(guān)
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10JVM的垃圾回收機制詳解和調(diào)優(yōu)
- 01-10Java Socket編程(三) 服務(wù)器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10J2SE 1.5版本的新特性一覽
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java Socket編程(四) 重復(fù)和并發(fā)服務(wù)
- 01-10Java經(jīng)驗點滴:處理沒有被捕獲的異常
隨機閱讀
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結(jié)
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05織夢dedecms什么時候用欄目交叉功能?