面向?qū)ο缶幊逃腥筇匦裕悍庋b、繼承、多態(tài)。
站在用戶的角度思考問題,與客戶深入溝通,找到景泰網(wǎng)站設(shè)計(jì)與景泰網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名與空間、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋景泰地區(qū)。
封裝隱藏了類的內(nèi)部實(shí)現(xiàn)機(jī)制,可以在不影響使用的情況下改變類的內(nèi)部結(jié)構(gòu),同時(shí)也保護(hù)了數(shù)據(jù)。對(duì)外界而已它的內(nèi)部細(xì)節(jié)是隱藏的,暴露給外界的只是它的訪問方法。
繼承是為了重用父類代碼。兩個(gè)類若存在IS-A的關(guān)系就可以使用繼承。,同時(shí)繼承也為實(shí)現(xiàn)多態(tài)做了鋪墊。那么什么是多態(tài)呢?多態(tài)的實(shí)現(xiàn)機(jī)制又是什么?請(qǐng)看我一一為你揭開:
所謂多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。因?yàn)樵诔绦蜻\(yùn)行時(shí)才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實(shí)現(xiàn)上,從而導(dǎo)致該引用調(diào)用的具體方法隨之改變,即不修改程序代碼就可以改變程序運(yùn)行時(shí)所綁定的具體代碼,讓程序可以選擇多個(gè)運(yùn)行狀態(tài),這就是多態(tài)性。練習(xí)(1):創(chuàng)建一個(gè)Cycle類,它具有子類Unicycle,Bycycle,Tricycle.演示每一個(gè)類型的實(shí)例都可以經(jīng)由ride()方法向上轉(zhuǎn)型為Cycle.
向上轉(zhuǎn)型就是允許將多種從同一基類的導(dǎo)出類看成同一類型。
多態(tài)方法調(diào)用就是允許一種類型表現(xiàn)出與其他相似類型之間的區(qū)別,只要他們是從同一基類導(dǎo)出而來的。這種區(qū)別由各個(gè)導(dǎo)出類型方法的具體不同實(shí)現(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)型只是看成,而不是強(qiáng)制轉(zhuǎn)換,所以最后方法調(diào)用的結(jié)果不同,這就是多態(tài)。
多態(tài)又稱之為動(dòng)態(tài)綁定。什么是動(dòng)態(tài)綁定?
與動(dòng)態(tài)綁定相反的是靜態(tài)綁定。c語言所有方法都是默認(rèn)靜態(tài)綁定。靜態(tài)綁定也稱為前期綁定,就是在程序運(yùn)行前就綁定完成。也就是說,代碼寫了什么樣,就是什么樣。
而動(dòng)態(tài)綁定是直到運(yùn)行時(shí)才去決定該方法調(diào)用該綁定哪個(gè)實(shí)體。
java中的所有static和final方法都是靜態(tài)綁定,其他的所有方法都是動(dòng)態(tài)綁定。
練習(xí)(2):在幾何圖形示例中添加@Override注解。
練習(xí)(3):在基類Shape.java中添加一個(gè)新方法,用于打印一條消息,但導(dǎo)出類中不要覆蓋這個(gè)方法。請(qǐng)解釋發(fā)生了什么?,F(xiàn)在,在其中一個(gè)導(dǎo)出類中覆蓋該方法,而在其他的導(dǎo)出類中不予覆蓋,觀察又有什么發(fā)生。最后,在所有的導(dǎo)出類中覆蓋這個(gè)方法。
練習(xí)(4):向Shapes.java中添加一個(gè)新的Shape類型,并在main()方法中驗(yàn)證:多態(tài)對(duì)新類型的作用是否與在舊類型中的一樣。
以上三個(gè)練習(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();//每個(gè)子類都調(diào)用了一次添加的新方法, // 因?yàn)樽宇惱^承父類自然把所有方法都繼承過去了,只不過沒有顯示出來, // 其實(shí)是隱式的存在的,子類調(diào)用的其實(shí)是繼承自父類的沒有重寫的方法, // 看起來像是調(diào)用了父類的方法 } Shape s = new Recf();//這里是聲明了一個(gè)Shape類型的引用,但實(shí)際的對(duì)象還是Recf. s.draw();//輸出的是Recf類重寫的方法,證明多態(tài)對(duì)新類的作用于在舊類中是一樣的 } } class Shape{//基類 public void draw(){} public void erase(){} public void newMethod(){ System.out.println("new method");//添加的新方法 } } class Circle extends Shape{ @Override//添加注解,一般IDE可以自動(dòng)添加 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ā)生改變,沒有重寫時(shí)該類的該方法與父類運(yùn)行結(jié)果相同 //無論重寫與否,其實(shí)調(diào)用的都是自身的方法 //只是沒有重寫時(shí)方法調(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{//是一種工廠,用以隨機(jī)獲取一種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()方法,并驗(yàn)證多態(tài)起作用了。
在練習(xí)(1)的代碼中給基類添加
public void wheels(){ System.out.println("輪子數(shù)量是" + num); }
然后在main中:
unicycle.wheels(); bicycle.wheels(); tricycle.wheels();
最后輸出結(jié)果都順利輸出了方法中的語句,證明多態(tài)確實(shí)起作用了。
練習(xí)(6):修改Music3.java,是what()方法成為根Object的toString()方法。試用System.out.pringtln()方法打印Instrument對(duì)象(不用向上轉(zhuǎn)型).
練習(xí)(7):向Music3.java添加一個(gè)新的類型Instrument,并驗(yàn)證多態(tài)性是否作用于所添加的新類型.
練習(xí)(8):修改Music3.java,使其可以向Shapes.java中的方式那樣隨機(jī)創(chuàng)建Instrument對(duì)象。
三個(gè)練習(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);//驗(yàn)證多態(tài)性是否適用于所添加的新類型,答案是確實(shí)適用。 } public static void tune(Instrument instrument){ instrument.play(Note.MIDDLE_C);//無論傳進(jìn)聲明子類,都播放MIDDLE_C } public static void tuneAll(Instrument[] e){ for (Instrument i : e) { tune(i); System.out.println(i.toString()); } } } class RandomInsFactory{//工廠類,用于隨機(jī)生成一個(gè)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() { // /添加一個(gè)toString方法,調(diào)用當(dāng)前what方法, // 子類會(huì)自動(dòng)繼承該方法并分別返回給自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(嚙齒動(dòng)物):Mouse(老鼠),Gerbil(鼴鼠),Hamster(大頰鼠),等等這樣一個(gè)的繼承層次結(jié)構(gòu)。在基類中,提供對(duì)所有的Rodent都通用的方法,在導(dǎo)出類中,根據(jù)特定的Rodent類型覆蓋這些方法,以便觀察它們執(zhí)行不同的行為。創(chuàng)建一個(gè)Rodent數(shù)組,填充不同的Rodent類型,然后調(diào)用基類方法,觀察發(fā)生了什么情況。
這跟前面Instrument的例子相似,在Instrument中有what()這個(gè)對(duì)所有Instrument都通用的方法,而在每個(gè)子類中我們都覆蓋了這個(gè)方法并賦予了不同的行為,最終在main中創(chuàng)建了Instrument數(shù)組,調(diào)用了基類方法,最后得到的結(jié)果是不同類調(diào)用基類方法得到的輸出是該類重寫后的結(jié)果。不再重復(fù)。
練習(xí)(10):創(chuàng)建一個(gè)包含兩個(gè)方法的基類。在第一個(gè)方法中可以調(diào)用第二個(gè)方法。然后產(chǎn)生一個(gè)繼承自該基類的導(dǎo)出類,且覆蓋基類中的第二個(gè)方法。為該導(dǎo)出類創(chuàng)建一個(gè)對(duì)象,將它向上轉(zhuǎn)型為基類并調(diào)用第一個(gè)方法,解釋發(fā)生的情況。
public class Test10 { public static void main(String[] args){ jilei j = new daochulei();//創(chuàng)建導(dǎo)出類的對(duì)象并轉(zhuǎn)型為基類 j.first();//調(diào)用第一個(gè)方法 //結(jié)果輸出daochulei is running //原因,就像前面提過的,導(dǎo)出類繼承了基類的所有東西,沒有重寫的方法隱藏了起來 //其實(shí)在daochulei中還隱士的有void first()這個(gè)方法里調(diào)用了自身重寫的second() //當(dāng)daochulei調(diào)用first()方法后,它就調(diào)用了自身重寫的second()方法。 //導(dǎo)出類調(diào)用基類方法其實(shí)不是真的調(diào)用,而是調(diào)用自身繼承自基類的方法, // 只不過這個(gè)方法沒重寫時(shí),內(nèi)部形式與基類相同 } } class jilei{ void first(){//調(diào)用第二個(gè)方法 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)出類中添加成員對(duì)象,并說明構(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 + "點(diǎn)" ); } } class Mouse extends Rodent{ private int sh; public Mouse(){ sh = 1000; System.out.println("Mouse"); } @Override public void bite() { System.out.println("造成傷害" +sh + "點(diǎn)" ); } } class Gerbil extends Mouse{ private int shang; public Gerbil(){ shang = 2000; System.out.println("Gerbil"); } @Override public void bite() { System.out.println("造成傷害" +shang + "點(diǎn)" ); } } class Hamster extends Gerbil{ private Mouse mouse = new Mouse();//成員對(duì)象 //該類初始化輸出結(jié)果 //Rodent // Mouse // Gerbil // Rodent // Mouse // Hamster //可以分析出,初始化時(shí)先調(diào)用基類的構(gòu)造方法, // 然后初始化成員變量,因?yàn)槠渲杏蠱ouse這個(gè)成員對(duì)象,所有對(duì)Mouse進(jìn)行初始化, // 完成后再調(diào)用自身的構(gòu)造方法 private int hai; public Hamster(){ hai = 3000; System.out.println("Hamster"); } @Override public void bite() { System.out.println("造成傷害" + hai + "點(diǎn)" ); } }
總結(jié)
以上就是本文關(guān)于Java編程—在測(cè)試中考慮多態(tài)的全部?jī)?nèi)容,希望對(duì)大家有所幫助。歡迎參閱:Java面向?qū)ο缶幊蹋ǚ庋b/繼承/多態(tài))實(shí)例解析、Java實(shí)現(xiàn)微信公眾平臺(tái)朋友圈分享功能詳細(xì)代碼、Java編程BigDecimal用法實(shí)例分享等,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!