- Learning Java by Building Android Games
- John Horton
- 792字
- 2021-07-23 19:02:34
Inheritance mini-app
We have looked at the way we can create hierarchies of classes to model the system which fits our game. So, let's try out some simple code that uses inheritance. The completed code is in the chapter 8
folder of the code download. It is called InheritanceExample
.
Create a new project called Inheritance
. Create three new classes in the usual way. Name one AlienShip
, another Fighter
, and the last one Bomber
.
Next is the code for the AlienShip
class. It is very similar to our previous class demo AlienShip
. The differences are that the constructor now takes an int
parameter which it uses to set the shield strength.
The constructor also outputs a message to the logcat window, so we can see when it is being used. The AlienShip
class also has a new method, fireWeapon
that is declared abstract
. This guarantees that any class that subclasses AlienShip
must implement their own version of fireWeapon
. Notice the class has the abstract
keyword as part of its declaration. We must do this because one of its methods also uses the keyword abstract
. We will explain the abstract
method when discussing this demo and the abstract
class when we talk about polymorphism after this demo.
Let's just see it in action. Create a class called AlienShip
and type this code.
public abstract class AlienShip { private static int numShips; private int shieldStrength; public String shipName; public AlienShip(int shieldStrength){ Log.i("Location: ", "AlienShip constructor"); numShips++; setShieldStrength(shieldStrength); } public abstract void fireWeapon(); // Ahhh! My body, where is it? public static int getNumShips(){ return numShips; } private void setShieldStrength(int shieldStrength){ this.shieldStrength = shieldStrength; } public int getShieldStrength(){ return this.shieldStrength; } public void hitDetected(){ shieldStrength -= 25; Log.i("Incoming: ", "Bam!!"); if (shieldStrength <= 0){ destroyShip(); } } private void destroyShip(){ numShips--; Log.i("Explosion: ", "" + this.shipName + " destroyed"); } }
Now we will implement the Bomber
class. Notice the call to super(100)
. This calls the constructor of the superclass with the value for shieldStrength
. We could do further specific Bomber
initialization in this constructor, but for now, we just print out the location, so we can see when the Bomber
constructor is being executed. Also, because we must, implement a Bomber
specific version of the abstract fireWeapon
method. Create (if you haven't already) a class called Bomber
and type this code.
public class Bomber extends AlienShip { public Bomber(){ super(100); // Weak shields for a bomber Log.i("Location: ", "Bomber constructor"); } public void fireWeapon(){ Log.i("Firing weapon: ", "bombs away"); } }
Now we will implement the Fighter
class. Notice the call to super(400)
. This calls the constructor of the superclass with the value for shieldStrength
. We could do further specific Fighter
initialization in this constructor but for now, we just print out the location, so we can see when the Fighter
constructor is being executed. We also, again because we must, implement a Fighter
specific version of the abstract fireWeapon
method. Create a class called Fighter
and type this code.
public class Fighter extends AlienShip{ public Fighter(){ super(400); // Strong shields for a fighter Log.i("Location: ", "Fighter constructor"); } public void fireWeapon(){ Log.i("Firing weapon: ", "lasers firing"); } }
And here is our code in the onCreate
method of MainActivity
. As usual, enter this code after the call to super.onCreate
. This is the code which uses our three new classes. The code looks quite ordinary, nothing new, it is the output which is interesting.
Fighter aFighter = new Fighter(); Bomber aBomber = new Bomber(); // AlienShip alienShip = new AlienShip(500); // Can't do this AlienShip is abstract - // Literally speaking as well as in code // But our objects of the subclasses can still do // everything the AlienShip is meant to do aBomber.shipName = "Newell Bomber"; aFighter.shipName = "Meier Fighter"; // And because of the overridden constructor // That still calls the super constructor // They have unique properties Log.i("aFighter Shield:", ""+ aFighter.getShieldStrength()); Log.i("aBomber Shield:", ""+ aBomber.getShieldStrength()); // As well as certain things in certain ways // That are unique to the subclass aBomber.fireWeapon(); aFighter.fireWeapon(); // Take down those alien ships // Focus on the bomber it has a weaker shield aBomber.hitDetected(); aBomber.hitDetected(); aBomber.hitDetected(); aBomber.hitDetected();
Run the app and you will get the following output in the logcat window.
Location:﹕ AlienShip constructor Location:﹕ Fighter constructor Location:﹕ AlienShip constructor Location:﹕ Bomber constructor aFighter Shield:﹕ 400 aBomber Shield:﹕ 100 Firing weapon:﹕ bombs away Firing weapon:﹕ lasers firing Incoming:﹕ Bam!! Incoming:﹕ Bam!! Incoming:﹕ Bam!! Incoming:﹕ Bam!! Explosion:﹕ Newell Bomber destroyed
We can see how the constructor of the subclass can call the constructor of the superclass. We can also clearly see that the individual implementations of the fireWeapon
method work exactly as expected.