第25節 - Java & LibGDX: super keyword
這一節我會介紹Java的一個保留字(keyword) "super",super保留字可以用來呼叫父類別的成員。
因為Java是一種物件導向程式語言,只要一個子類別(Son)繼承(inheritance- extends)父類別(Parent),子類別就可以用父類別的成員(例如父類別的方法)。
為甚麼要學Java的保留字super?
最主要原因是因為在寫LibGDX遊戲過程中,我們會常常遇到super保留字。
第一次在本網站出現super應該是第15節 - @Override的用法和意思,大家可以在下圖發現所有resize(), render(), pause(), resume()和dispose()方法內都會用到super,我會在這一節詳細介紹。
以下會用幾個簡單例子一步一步解釋super的用法:
Java: 例子1
首先在Eclipse建立一個MyDemo25 project,再建立第1個Class(MyDemo25_1),我們建立一個父類別(Parent)和一個子類別(Son),把子類別(Son)繼承(extends)父類別(Parent),Son物件(s)就可以用Parent類別的methodP1()方法,如下圖:
- 建立一個父類別(Parent),再建立一個methodP1()方法。
- 建立一個子類別(Son),再建立一個methodS1()方法。
- 執行程式:
s.methodP1()呼叫Parent類別內的methodP1()方法。
s.methodS1()呼叫自己Son類別內的methodS1()方法。
Java: 例子2
在Son類別內覆蓋methodP1()方法,如下圖:
- 建立一個父類別(Parent),再建立一個methodP1()方法。
- 建立一個子類別(Son),再建立一個methodS1()方法。
- 再在子類別(Son)內建立一個methodP1()方法。
- 執行程式:
s.methodP1()呼叫自己Son類別內的methodP1()方法。
s.methodS1()呼叫自己Son類別內的methodS1()方法。
注意,我在第14節 - Type Casting, Upcasting & Downcasting介紹過,執行s.methodP1()方法時,程式會選擇Son類別內的methodP1()方法,這就叫做Polymorphism - Method Overriding。
Java: 例子3
在Son類別的methodS1()方法內用super.methodP1()呼叫Parent類別內的methodP1()方法,如下圖:。
- 建立一個父類別(Parent),再建立一個methodP1()方法。
- 建立一個子類別(Son),再建立一個methodS1()方法。
- 再在子類別(Son)內建立一個methodP1()方法,在methodP1()方法內用super.methodP1()呼叫Parent類別內的methodP1()方法。
注意,在Son的methodP1()方法內,大家除了可以用super.methodP1()呼叫Parent類別內的methodP1()方法外,還可以加入自己須要的程式,這也是很多程式又要覆寫子類別方法,又要加入自己須要的程式的原因。 - 執行程式:
s.methodP1()呼叫自己Son類別內的methodP1()方法。
s.methodS1()呼叫Parent類別內的methodP1()方法,再呼叫自己Son類別內的methodS1()方法。
Java: 例子4
這次把父類別(Parent)轉為抽象類別(Abstract Class),我在第23節 - LibGDX: Advanced Game Menu Screen (Using Abstract Screen)介紹過抽象類別的方法,在Parent抽象類別內建立一個抽象方法methodP1(),再在Son類別內定義methodP1()方法內容,如下圖:。
- 把父類別(Parent)轉為抽象類別(Abstract Class),再建立一個methodP1()抽象方法。
- 建立一個子類別(Son),再建立一個methodS1()方法。
- 再在Son類別內定義methodP1()方法內容。
- 執行程式:
s.methodP1()呼叫自己Son類別內的methodP1()方法。
s.methodS1()呼叫自己Son類別內的methodS1()方法。
Java: 例子5
這次再加入祖父抽象類別(Grandparent),在Grandparent抽象類別內建立一個抽象方法methodG1(),再在Parent類別內定義methodG1()方法內容,再在Son類別內覆寫methodG1()方法內容,如下圖:
- 加入祖父抽象類別(Grandparent),在Grandparent抽象類別內建立一個抽象方法methodG1()。
- 建立一個父類別(Parent),再在Parent類別內定義methodG1()方法內容。
- 建立一個子類別(Son),再建立一個methodS1()方法。
- 再在Son類別內覆寫methodG1()方法內容。
- 執行程式:
s.methodG1()呼叫自己Son類別內的methodG1()方法。
Java: 例子6
在Son類別的methodG1()方法內用super.methodG1()呼叫Parent類別內的methodG1()方法,如下圖:
- 加入祖父抽象類別(Grandparent),在Grandparent抽象類別內建立一個抽象方法methodG1()。
- 建立一個父類別(Parent),再在Parent類別內定義methodG1()方法內容。
- 建立一個子類別(Son),再覆寫methodG1()方法內容,在methodG1()方法內用super.methodG1()呼叫Parent類別內的methodG1()方法。
- 執行程式:
s.methodG1()呼叫Parent類別內的methodG1()方法。
Java: 例子7
例子7和例子6相似,我們只把Son類別內的methodG1()方法刪除,s.methodG1()就會呼叫Parent類別內的methodG1()方法,如下圖:
- 加入祖父抽象類別(Grandparent),在Grandparent抽象類別內建立一個抽象方法methodG1()。
- 建立一個父類別(Parent),再在Parent類別內定義methodG1()方法內容。
- 建立一個子類別(Son),刪除methodG1()方法。
- 執行程式:
s.methodG1()呼叫Parent類別內的methodG1()方法。
Java: 例子8
這個例子就是最多人出錯的一個,與例子6和例子7相似,在Son類別內有覆寫methodG1()方法,但沒有提供內容或super.methodG1(),雖然程式可以執行,但結果就會出錯,如下圖:
- 加入祖父抽象類別(Grandparent),在Grandparent抽象類別內建立一個抽象方法methodG1()。
- 建立一個父類別(Parent),再在Parent類別內定義methodG1()方法內容。
- 建立一個子類別(Son),覆寫methodG1()方法,但不提供內容或super.methodG1()。
- 執行程式:
結果空白。
LibGDX: 例子1
大家看完以上八個Java例子,把以上學到的用在LibGDX上,其實它們的關係如下:
- Grandparent=ApplicationListener
- Parent=Game
- Son=MyDemo25
- 把menuscreen.png和splashscreen.png傳入Android/assets/內。
- DesktopLauncher是PC Desktop的Starter Class,我們在DesktopLauncher內設定顯示的大小為459x600px。
- 這個Game2類別是複製LibGDX官方的Game類別,因為我會在LibGDX - 例子2內嘗試更改內容,大家請注意。
- 把LibGDX官方的Game類別內容複製到Game2類別內。
- 把MyDemo25_9 extends Game2 (不是Game!)。
- 只覆寫Game2類別的create()方法,其他不理會 (這個就是以上介紹的Java例子7)。
- 把Game2 (不是Game!)傳入SplashScreen的話Constructor內。
- 注意,因為SplashScreen是實作Screen介面,而不是繼承Game抽象類別,在Screen介面內的show(), render(), resize(), pause(), resume()和hide()都沒有定義內容,而Game抽象類別內除了create()方法沒有定義內容外,其他都定義了內容。
所以就算SplashScreen實作Screen介面,只要覆寫show(), render(), resize(), pause(), resume()和hide()方法,而內容可以空白或設計自己須要的程式。
- MenuScreen和SplashScreen一樣,只要覆寫show(), render(), resize(), pause(), resume()和hide()方法,而內容可以空白或設計自己須要的程式。。
LibGDX: 例子2
這個例子嘗試更改Game2抽象類別的內容,把render()方法內的內容刪除,如下圖:
- 更改Game2抽象類別的內容,把render()方法內的內容刪除。
因為沒有了預設的screen.render()方法,所以屏幕顯示黑色,如下圖:
LibGDX: 例子3
這個例子嘗試把Game2抽象類別內的內容複製到MyDemo25_9類別內,如下圖:
- 把Game2抽象類別內的內容複製到MyDemo25_9類別內(這個就是以上介紹的Java例子5)。。
LibGDX: 例子4
這個例子嘗試把Game2抽象類別內的內容更改為super,如下圖:
- 更改為super後,就會呼叫Game2抽象類別內的方法(這個就是以上介紹的Java例子6)。
LibGDX: 例子5
- 這個例子就是最多人出錯的一個,覆寫Game2抽象類別內的方法,但不提供內容或super(這個就是以上介紹的Java例子8)。
LibGDX: 總結
- 例子1,3和4是正確的。
- 例子2是錯誤的,因為我固意更改LibGDX Game 類別官方內容。
- 例子5就是最多人出錯的一個,因為覆寫Game抽象類別內的方法,但不提供內容或super。