java继承与多态_Java继承与多态
感慨一下,到了現在感覺Java里面很多東西都是模模糊糊,不能這樣了,一點點解決吧。今天看了繼承與多態的一些內容,感覺看得很淺,先寫下來,算是鞏固,如果后面看到更好的內容,再慢慢加上去。
繼承與多態,他們是面向對象里圈里面的兩個好朋友呀。我想,這一部分的內容應該是最常用也是最常見的了吧。
繼承是什么
說到繼承,我最先想到的是可以避免代碼重復,也就是代碼復用。其實,除了這個作用之外,繼承還給我們提供了一個強大的武器“多態”,但是我以前卻常常忽略它,真是不好意思啊。
舉例子吧,有兩個類:SamsungBrand,AppleBrand,這是兩個品牌,那么對于一個品牌,我們可能想知道它是什么時候創立的,他的名稱是什么,所以可以在這兩個類中分別設立兩個變量,一個是年份(String year),另一個是名稱(String brand),然后顯然要為這兩個變量設置set和get方法。代碼很簡單,我就不貼了,可以想象的到,兩個類中都有year和brand。嗯,這樣看起來也不是很麻煩,但是如果要寫100個品牌的話,那就非常累了。
所以我們可以提取這些類的公共點,然后放在一個Brand類中,并且讓具體的品牌去繼承這個Brand就大大的減少了代碼的冗余。
所以,記住一句話:繼承的是共同的行為
那么,下面我們來就來看看多態吧,這是很重要的。前面已經說到,一個類A可以繼承另一個類B(通過extends關鍵字),那么A是子類,B是父類。子類和父類的關系我們可以說成“是一個”(is-a)。
比如前面的例子:SamsungBrand和AppleBrand都是Brand的子類,那么它們的關系就是:
SamsungBrand is a Brand,AppleBrand is a Brand。
這個很重要。
所以說,如果我們這樣寫代碼:
Brand samsung = new SamsungBrand();//從左往右,符合is-a
Brand apple = new AppleBrand();
顯然這是符合is-a的,所以編譯器說,你可以通過。
但是,如果我們這樣寫:
SamsungBrand samsung = new Brand();//我一定會是samsung嗎?
AppleBrand apple = new Brand();//我一定會是apple嗎?
一個Brand對象可能是Samsung的,也可能是Apple的,所以編譯器是不會讓這樣的代碼通過的。
但此時,會有一個問題:
Brand brand = newSamsungBrand();
SamsungBrand samsung= brand;
代碼顯然是不給編譯通過的,編譯器查到brand是Brand類型的,那么brand不一定是Samsung的,所以不會讓著兩行代碼編譯通過。但是作為代碼的編寫者,我很清楚的知道,這個brand就是samsung,那么有什么辦法讓編譯器閉嘴呢?
Java提供了一種方法:扮演(Cast),讓brand扮演SamsungBrand類型的對象,告訴編譯器不要啰嗦。
Brand brand = newSamsungBrand();
SamsungBrand samsung= (SamsungBrand)brand;
這樣的話,著兩行代碼就會編譯通過。但是要注意,如果讓對象“扮演”了,就意味著,后果自負!
想想看,如果把第一行代碼改成new AppleBrand(),但是下面一行代碼不變,因為用了“扮演”,編譯器不會再啰嗦,可是,在運行的時候,哇,出錯了!JVM拋出了ClassCastException異常。
Exception in thread "main" java.lang.ClassCastException: AppleBrand cannot be cast to SamsungBrand
有了上面的知識儲備,相信下面講起來會輕松一點。對了,上面的內容不是廢話!is-a懂了很重要,Cast也很重要,懂了這些可以讓你寫的代碼更加靈活并且易于維護。
真的嗎?我們來看一下:設計一個static方法,這個方法傳入某一個品牌的對象,然后輸出品牌的誕生的年份和名稱。
public static voidshow(SamsungBrand brand){
System.out.println(brand.getYear()+","+brand.getName());
}public static voidshow(AppleBrand brand){
System.out.println(brand.getYear()+","+brand.getName());
}
上面是一種不錯的解決方法,但是當有更多的品牌的時候,也許就不會覺得這樣寫好了。
這個時候,我們可以這樣寫:
public static voidshow(Brand brand){
System.out.println(brand.getYear()+","+brand.getName());
}
然后分別傳入兩種品牌的對象,依然會正確!這是為什么?
答案就是:方便的不得了的 “多態” 幫了大忙!
當傳進一個AppleBrand對象的時候,實際上brand只是掛著Brand的牌子,實際上做的是AppleBrand的工作,調用getYear()實際上是調用AppleBrand中的getYear()。
還有一個小內容,我在用eclipse編寫繼承代碼的時候,有時候重寫(override)某個方法是,IDE會自動在這個方法的前面加上一個@Override,然后我把它刪了,代碼依然正常。那這個代碼還有啥用呢?
其實吧,這個小東西還確實挺有用的(JDK5之后出現的,話說回來,沒用人家還不早刪了)!
加入說新增加一個方法:show(),用來顯示品牌信息。在Brand中,show()設定為空方法,后面繼承的時候,如果不小心,將show寫成了Show,額..結果可想而知了哈。
為了避免這種錯誤呢,可以讓我們親愛的編譯器在編譯的時候幫我們檢查一下,這個是不是override,那怎么告訴編譯器要不要檢查呢?
哈,就是@Override!!!
下面再說一下抽象方法和抽象類:
剛剛說到了show()是一個空方法,由子類去實現,假設是在一個很大的部門開發,一個人開發Brand,剩下n個人開發其子類,很有可能其中會有朋友忘記實現show()這個方法。如果要一個個去通知,會很痛苦的(打電話不接,發短信不會,啊啊啊啊)。該怎么辦呢?
抽象方法就是用來決絕這個問題的:使用abstract(小寫的哦!!)關鍵字表示該方法為抽象方法,這個方法不必寫{}塊,直接用“;”結束就行了!
比如:
public abstract void show();
這樣定義之后,子類如果不去實現這個方法,會報錯的,哈哈,方便!(額,不全面,實際上作為子類有兩種選擇:1.乖乖實現;2.繼續把它聲明為abstract)
如果一個類中,有抽象方法,那么:該類一定要也聲明為抽象類。
并且,抽象類是不能實例化的!(new)
這是因為抽象類是一個為完成(實現)的類。
還有兩點就是:雖然抽象方法可能沒有完成,但是可以使用;雖然抽象類不可以實例化,但是可以聲明!
繼承進階
“進階”看上去就高端大氣上檔次。其實沒有這么夸張,僅僅是將一些易錯的內容放進來。
內容1:
內容2:
構造函數是最常見的了:如果我們在類中啥都不定義,那么系統會為我們定義一個無參的默認構造函數;但是如果我們在類中定義了任何一種構造函數,系統將不再為我們構造默認構造函數。
加入了繼承的概念后,我們要記住一點,如果子類構造函數中沒有指定執行父類中那個構造函數,默認會調用父類中無參構造函數,也就是說:
classSome{
Some(){
System.out.println("this is some");
}
}class Other extendsSome{
Other(){
System.out.println("this is other");
}
}//上面的代碼等價于
classSome{
Some(){
System.out.println("this is some");
}
}class Other extendsSome{
Other(){super();
System.out.println("this is other");
}
}
從這個代碼也可以看出,如果定義了一個Other對象,實際上還是先執行Other(),但是呢,在第一步執行了super(),調用了父類的無參構造函數。
可以在子類的構造函數中,利用super,調用父類指定的構造函數(有參無參隨便你),但是,記住一定要放在第一句!!!!
內容3:
下面來看一下final,這個東西類似于C++中的const,定義之后不可以改變變量的值,可以先聲明后賦值。
可以將這個final放在方法前,也可以放在類前,它的作用,該方法/類,不可以再被重寫/繼承。
經常會看到final和static連在一起使用,一開始不能理解,現在似乎有一點明白了:我們在設計類的時候,可能經常會用到一些常量,假設用到了一個對象p,我們可以用final將其定義為常量,那么在類實例化之后,這個就不會再改變(是我們想要的結果),但是同時也有一個問題,每實例話一次,可能都要為這個p分配空間,而實際上,我們只需要一個p就足夠了,不必浪費內存。要解決這個問題,只需要將final和static連起來用就可以啦。
額…寫的累死,這一部分內容就先到這里了。
總結
以上是生活随笔為你收集整理的java继承与多态_Java继承与多态的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: neo4j java label_Neo
- 下一篇: 在java中使用关键字导入包_java中
