第六章 繼承與多態html
所謂繼承就是避免多個類間重複定義共同行爲。java
1.重複在程序設計上就是很差的信號,若是要改進就能夠把相同的程序代碼提高爲父類。linux
2.使用新的關鍵字extends表示繼承而且擴充原先沒有的行爲。繼承的好處就是若要修改,無需在繼承的子類中去修改。
==注意==private成員會被繼承,不過沒法直接存取,必須經過父類提供的方法存取。git
3.子類只可繼承一個父類,子類與父類之間會有is-a的關係。
例如:ide
Role role1 = new SwordsMan() SwordsMan swordsman = role1; //x SwordsMan swordsman = (SwordsMan)role1; //ok
第二條語句會出現編譯錯誤。第三條語句在執行時會拋出classcastexception。函數
4.多態學習
使用單一接口操做多種類型的對象this
5.從新定義.net
定義與父類中相同的方法部署,但執行的內容不一樣(override)。
在JDK5以後,內建標註設計
@Override
若是在子類的某個方法前標註,表示要求編譯程序檢查該方法是否是從新定義了父類的某個方法。
6.抽象方法,抽象類
若是某方法區塊中真的沒有任何程序的代碼操做,可使用
abstract
標示該方法爲抽象方法。
==注意==抽象類不能使用new生成對象
7.protected成員
相同包中的類能夠直接存取,不一樣包中的類能夠在繼承後的子類中直接存取。
public / package / protected / private
==提示==依照權限由小至大來區分就是private,無關鍵字,protected,與public。
8.從新定義的細節
若是想取得父類中的方法定義,能夠在調用方法前加上super關鍵字。
可使用super調用父類方法,不能定義爲private。
==注意==從新定義方法時,對於父類中的方法權限,只能擴大不能縮小。
9.再看構造函數
構造函數能夠重載,父類中可重載多個函數。若是想執行父類中某構造函數,可使用super()指定。
==注意==this()與super()只能擇一調用,並且要在構造函數第一行執行。
10.再看final關鍵字
class前也能夠加上final關鍵字,表示這個類是最後一個類,不會再有子類,即就是不能被繼承。
定義方法時,也可使用,表示子類不能夠從新定義final方法。
11.java.lang.Object
若是繼承時沒有使用extends關鍵字指定任何類,那麼繼承的是java.lang.Object。
12.instanceof運算符能夠用來斷定對象是否由某個類建立,左操做數是對象,右操做數是類。
13.垃圾收集
沒法經過變量引用的對象就是GC認定的垃圾對象。
垃圾回收前會調用finalize()方法,但因爲調用時機沒法肯定,建議不要使用finalize()方法。
1.使用接口(interface)定義行爲
類要操做接口,必須使用implemnts關鍵字。
操做接口時,對接口中定義的方法有兩種處理方式,一是操做接口定義的方法,二是再度將方法標示爲abstract。
==繼承與操做接口的區別==:繼承時有「是一種」的關係,操做接口則表示「擁有行爲」。
2.若是增長新的需求,原有的程序無需修改,只須要針對新需求撰寫程序,就是有彈性,具備可維護性的程序
3.類能夠操做的兩個以上的類,也就是擁有兩種以上的行爲。
4.接口默認
在接口中枚舉常數,必定要使用=指定值,不然編譯錯誤。
==注意==要在類中定義枚舉常數也是能夠的,不過要明確寫出public static final。
5.匿名內部類
在撰寫java程序的時候,會面臨臨時繼承某個類或操做某個接口並創建實例的需求,因爲只使用一次,不須要定義名稱。可使用匿名類。
在JDK8以前要在匿名內部類中存取局部變量,必須是final,不然編譯錯誤。
==注意==局部變量的生命週期比對象短。java的作法是傳值。
6.使用enum枚舉常數
enum實際上定義了類,而enum中列舉的常數,其實是public static final ,且爲枚舉類型實例,沒法撰寫程序直接實例化枚舉類型,由於構造函數權限設定設定爲private。
在第六章剛開始時,書上提到不能濫用繼承,那麼濫用繼承會致使什麼樣的後果?
首先我上網搜索了一下怎麼樣纔算濫用繼承。
兩個斷定是不是濫用繼承的重要依據:
1.若是一個類從核心用意和設計初衷上自然是另外一個類的子類,這種繼承是天經地義的,並不存在破壞封裝的說法。
2.在容許多繼承的語言裏,若是一個類須要使用到來自另外一個父類(特質)的「全體」字段和方法,或都反過來講,把某個父類(特質)的全體成員賦予另外一個類時,若是從這兩個類的設計用意和表明的概念上沒有任何的違和感,那麼,這時候使用繼承也是正當的,沒有破壞封裝的嫌疑。
那麼危害有哪些呢?
劍士:(Justin, 1, 200) 魔法師:(Monica, 1, 100)
而是出現以下錯誤:
class Role { private String name; private int level; private int blood; public int getBlood() { return blood; } public void setBlood(int blood) { this.blood = blood; } public int getLevel() { return level; } public void setLevel(int level) { this.level= level; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void fight(){} } class SwordsMan extends Role{ public void fight(){ System.out.println("揮劍攻擊"); } } class Magician extends Role{ //private String fight; public void fight(){ System.out.println("魔法攻擊"); } public void cure(){ System.out.println("魔法治療"); } } public class RPG3 { public static void main(String[] args) { SwordsMan swordsMan=new SwordsMan(); swordsMan.setName("Justin"); swordsMan.setLevel(1); swordsMan.setBlood(200); Magician magician=new Magician(); magician.setName("Monica"); magician.setLevel(1); magician.setBlood(100); drawFight(swordsMan); drawFight(magician); } static void drawFight(Role role){ System.out.println(role.getName()); role.fight(); } }
運行結果:
1.在同一個包(Array)中創建兩個文件
2.並在兩個代碼段的開頭都加入了
Package Array;
表示在同一個包中。
3.開始編譯Guest代碼段,出現錯誤
緣由:未先編譯父類的方法。
4.先編譯父類的方法ArrayList.java在編譯Guest.java:
5.最後在運行時又出現了錯誤如上圖
6.修改以下:須要將寫上 package的名稱.代碼段名稱
(而且運行)
問題解決~!
代碼提交過程截圖:
代碼量截圖:
腳本截圖
緣由:linux的命令掌握的還不夠熟練,不少命令由於不經常使用就容易忘記。
緣由:這個我如今也不太懂,但願老師能講解一下疑惑。
緣由:看書的時候這裏沒有仔細閱讀,看書上給出的例子,不夠熟練應用於實例中,還不夠熟練掌握,作到觸類旁通。
在第六章中瞭解了繼承的目的,繼承就是避免多個類間重複定義共同行爲,而且在修改過程當中也避免了不少麻煩。還了解了多態與繼承的關係,而且經過閱讀教材大概知道了如何從新定義方法,從新定義時且若要取得父類中的方法定義,對於父類的方法權限,只能擴大但不能縮小。還知道了java.lang.Object是全部類追溯到最上層的父類。垃圾收集就是沒法經過變量參考的對象,就是GC認定的垃圾對象。在第七章中,舉例子介紹了接口定義行爲,瞭解了接口的多態操做。兩種方法的枚舉常數。
此次考試比前兩次的成績提升了2分,很開心。由於此次看書看得比較仔細,因此翻書找的時候沒有浪費太多時間,因此時間上相對充裕了,題也寫完了。還須要在代碼上多下功夫,作到天天都要敲代碼。
public class Role { private String name; private int level; private int blood; public int getBlood() { return blood; } public void setBlood(int blood) { this.blood=blood; } public int getLevel() { return level; } public void setLevel(int level){ this.level=level; } public String getName() { return name; } public void setName(String name) { this.name=name; } }
接着使用SwordsMan能夠以下繼承:
==出現了新的關鍵字extends==,表示會擴充Role的行爲,也就是繼承,擴充了本來沒有的fight行爲。
Magician也能夠進行繼承:
p178頁 定義的ArrayList類,能夠不限長度收集對象,每次收集的對象會放在next索引處,使用size()方法得知已收集的對象個數。
==注意==若是使用無參數構造函數,則默認容量爲16。
p186
定義的抽象類,這個類是不完整的,因此顯示輸入輸出就不能操做。
p187繼承抽象類GuessGame:
將3個代碼段放在同一個包下(Iheritance)
p186-187猜數字程序
也是將代碼片斷放在同一個package中,而後分別編譯,最後運行。
p197-201
Oceanworld程序,瞭解了接口和繼承的區別,以及優點。並瞭解了
interface
implements
關鍵字的定義及用法。繼承會有「是一種」關係,操做接口則表示「擁有行爲」因此會優先考慮接口而不是繼承。
課本編海洋的程序:
在輸入p202頁Airplane代碼段時
課本上代碼出現錯誤:
package OceanWorld1; public class Seaplane implements Swimmer,Flyer { private String name; public Seaplane(String name) { this.name = name; } @Override public void fly() { System.out.printf("海上飛機 %s 在飛%n", name); } @Override public void swim() { System.out.printf("海上飛機 %s 航行海面%n", name); } }
按照課本輸入的Airplane.java可是代碼爲:
public class Seaplane ....
因此從新創建文件名,並進行編譯,以下修改編譯正確:
p209頁程序:
p216
使用了匿名內部類。
與209頁程序做對比,使用enum定義,不像以前play()方法能夠傳入任何int值,因此不須要使用default進行檢查。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 15/15 | 1/1 | 23/26 | |
第二週 | 208/240 | 2/2 | 35/38 | |
第三週 | 376/584 | 3/3 | 32/38 | |
第四周 | 823/1407 | 4/4 | 28/30 |
嘗試一下記錄「計劃學習時間」和「實際學習時間」,到期末看看能不能改進本身的計劃能力。這個工做學習中很重要,也頗有用。
耗時估計的公式
:Y=X+X/N ,Y=X-X/N,訓練次數多了,X、Y就接近了。
計劃學習時間:28小時
實際學習時間:30小時