© Doug Winnie 2021
D. WinnieEssential Java for AP CompScihttps://doi.org/10.1007/978-1-4842-6183-5_55

55. Class, Extend Thyself!

Doug Winnie1  
(1)
Mission Hills, KS, USA
 

With our basic class created for the mage, we can look at other characters in our game and see how they compare to each other. We can see from their character sheets that they each have different skills and rules that govern how these skills are populated with values at the time of instantiation and construction.

The Mage class defines strength, intelligence, agility, and wisdom as the main fields and then uses a set of calculations to create their values and determine hit points and mana:
public class Mage {
    // Name
    public String name;
    // Skill attributes
    public int strength;
    public int intelligence;
    public int agility;
    public int wisdom;
    // Health and magic
    public int maxHitPoints;
    public int hitPoints;
    public int maxMana;
    public int mana;
    Mage(String newName) {
        // Constructor
        name = newName;
        strength = 7;
        intelligence = 15;
        agility = 8;
        wisdom = 10;
        strength += (int) (Math.random() * 6 + 1);
        intelligence += (int) (Math.random() * 6 + 1);
        agility += (int) (Math.random() * 6 + 1);
        wisdom += (int) (Math.random() * 6 + 1);
        maxHitPoints = hitPoints = strength;
        maxMana = mana = intelligence + (wisdom * 2);
        System.out.println("A new mage named " + name + " has been created!");
    }
    public void showStats() {
        System.out.println("””””””””””””””””””””””””””””””””””");
        System.out.println(name + ", a mage:");
        System.out.println("    Strength: " + strength);
        System.out.println("Intelligence: " + intelligence);
        System.out.println("     Agility: " + agility);
        System.out.println("      Wisdom: " + wisdom);
        System.out.println("  Hit Points: " + hitPoints + " / " + maxHitPoints);
        System.out.println("        Mana: " + mana + " / " + maxMana);
        System.out.println();
    }
}
Now, if we look at the Fighter class , we have a different set of skills that are used. The Fighter class defines strength, intelligence, agility, and constitution instead of wisdom. The calculations to determine their initial values and the amount of hit points and mana are also different:
public class Fighter {
    // Name
    public String name;
    // Skill attributes
    public int strength;
    public int intelligence;
    public int agility;
    public int constitution;
    // Health and magic
    public int maxHitPoints;
    public int hitPoints;
    public int maxMana;
    public int mana;
    Fighter(String newName) {
        // Constructor
        name = newName;
        strength = 15;
        intelligence = 7;
        agility = 8;
        constitution = 10;
        strength += (int) (Math.random() * 6 + 1);
        intelligence += (int) (Math.random() * 6 + 1);
        agility += (int) (Math.random() * 6 + 1);
        constitution += (int) (Math.random() * 6 + 1);
        maxHitPoints = hitPoints = (strength * 2) + (constitution * 2);
        maxMana = mana = 0;
        System.out.println("A new fighter named " + name + " has been created!");
    }
    public void showStats() {
        System.out.println("””””””””””””””””””””””””””””””””””");
        System.out.println(name + ", a fighter:");
        System.out.println("    Strength: " + strength);
        System.out.println("Intelligence: " + intelligence);
        System.out.println("     Agility: " + agility);
        System.out.println("Constitution: " + constitution);
        System.out.println("  Hit Points: " + hitPoints + " / " + maxHitPoints);
        System.out.println("        Mana: " + mana + " / " + maxMana);
        System.out.println();
    }
}

When you look at these two, there is a lot that is in common between them. They both contain a name, strength, intelligence, agility, hit points, and mana fields. They also both have a showStats() method that displays the instance’s attribute values.

When you create classes, you can take things that are common for multiple classes and create superclasses. It works like this. If we create a class that has everything that is in common, we can then build what is unique for a Mage and a Fighter on top of what is common for both. When you create classes in this way, you can build on top of and include or extend the contents of these classes.

So, if we had a new class called PlayerCharacter , we can define that to include everything that is in common between Fighter and Mage:
public class PlayerCharacter {
    // Name
    public String name;
    // Skill attributes
    public int strength;
    public int intelligence;
    public int agility;
    // Health and magic
    public int maxHitPoints;
    public int hitPoints;
    public int maxMana;
    public int mana;
    PlayerCharacter() {
        System.out.println("A new player character has been created!");
    }
    public void showStats() {
    }
}

As you can see, only the things that are common across Mage and Fighter are included here. We define strength, intelligence, agility, hit points, and mana fields, and we have a constructor for the PlayerCharacter class, and we have a method for showStats() which doesn’t do anything yet.

Now we can use this class as the foundation for other classes, including Mage and Fighter. We can strip out the items that are already in the PlayerCharacter class in each of these two classes. First, we can do that with the Mage class by removing the definitions for name, strength, intelligence, agility, hit points, and mana:
public class Mage {
    // Skill attributes
    public int wisdom;
    Mage(String newName) {
        // Constructor
        name = newName;
        strength = 7;
        intelligence = 15;
        agility = 8;
        wisdom = 10;
        strength += (int) (Math.random() * 6 + 1);
        intelligence += (int) (Math.random() * 6 + 1);
        agility += (int) (Math.random() * 6 + 1);
        wisdom += (int) (Math.random() * 6 + 1);
        maxHitPoints = hitPoints = strength;
        maxMana = mana = intelligence + (wisdom * 2);
        System.out.println("A new mage named " + name + " has been created!");
    }
    public void showStats() {
        System.out.println("””””””””””””””””””””””””””””””””””");
        System.out.println(name + ", a mage:");
        System.out.println("    Strength: " + strength);
        System.out.println("Intelligence: " + intelligence);
        System.out.println("     Agility: " + agility);
        System.out.println("      Wisdom: " + wisdom);
        System.out.println("  Hit Points: " + hitPoints + " / " + maxHitPoints);
        System.out.println("        Mana: " + mana + " / " + maxMana);
        System.out.println();
    }
}
When you do this though in an IDE, you will get errors appear, because Java doesn’t know that you are building the Mage class on top of the PlayerCharacter class. Not yet at least:
../images/499634_1_En_55_Chapter/499634_1_En_55_Figa_HTML.jpg

We need to specifically define that we are building the Mage class on top of the PlayerCharacter class. We do that by changing the definition of the class on the first line.

When you build on top of another class, you are extending it, so we need to change the first line to read:
public class Mage extends PlayerCharacter {
When you do that, all the errors that we previously saw are resolved and go away, because everything that is part of the PlayerCharacter class is now included in the Mage class:
../images/499634_1_En_55_Chapter/499634_1_En_55_Figb_HTML.jpg
Let’s go to our Fighter class now. Let’s change the class definition at the top to include the PlayerCharacter class by changing the first line to read:
public class Fighter extends PlayerCharacter {
Now we can remove the items that are already in the PlayerCharacter class :
public class Fighter extends PlayerCharacter {
    // Skill attributes
    public int constitution;
    Fighter(String newName) {
        // Constructor
        name = newName;
        strength = 15;
        intelligence = 7;
        agility = 8;
        constitution = 10;
        strength += (int) (Math.random() * 6 + 1);
        intelligence += (int) (Math.random() * 6 + 1);
        agility += (int) (Math.random() * 6 + 1);
        constitution += (int) (Math.random() * 6 + 1);
        maxHitPoints = hitPoints = (strength * 2) + (constitution * 2);
        maxMana = mana = 0;
        System.out.println("A new fighter named " + name + " has been created!");
    }
    public void showStats() {
        System.out.println("””””””””””””””””””””””””””””””””””");
        System.out.println(name + ", a fighter:");
        System.out.println("    Strength: " + strength);
        System.out.println("Intelligence: " + intelligence);
        System.out.println("     Agility: " + agility);
        System.out.println("Constitution: " + constitution);
        System.out.println("  Hit Points: " + hitPoints + " / " + maxHitPoints);
        System.out.println("        Mana: " + mana + " / " + maxMana);
        System.out.println();
    }
}
Everything looks good , so let’s go to our Main class and update our main() method to create two instances of the Mage and Fighter class:
public class Main {
    public static void main(String[] args) {
        Mage myMage = new Mage("Francisco");
        myMage.showStats();
        Mage myOtherMage = new Mage("Jaana");
        myOtherMage.showStats();
        Fighter myFighter = new Fighter("Dupre");
        myFighter.showStats();
        Fighter myOtherFighter = new Fighter("Sentri");
        myOtherFighter.showStats();
    }
}
Now let’s run and see what the output is. Remember that the values are generated using a random number, so these results will vary from others:
A new player character has been created!
A new mage named Francisco has been created!
””””””””””””””””””””””””””””””””””
Francisco, a mage:
    Strength: 12
Intelligence: 17
     Agility: 9
      Wisdom: 16
  Hit Points: 12 / 12
        Mana: 49 / 49
A new player character has been created!
A new mage named Jaana has been created!
””””””””””””””””””””””””””””””””””
Jaana, a mage:
    Strength: 12
Intelligence: 16
     Agility: 11
      Wisdom: 15
  Hit Points: 12 / 12
        Mana: 46 / 46
A new player character has been created!
A new fighter named Dupre has been created!
””””””””””””””””””””””””””””””””””
Dupre, a fighter:
    Strength: 18
Intelligence: 9
     Agility: 12
Constitution: 12
  Hit Points: 60 / 60
        Mana: 0 / 0
A new player character has been created!
A new fighter named Sentri has been created!
””””””””””””””””””””””””””””””””””
Sentri, a fighter:
    Strength: 18
Intelligence: 12
     Agility: 13
Constitution: 11
  Hit Points: 58 / 58
        Mana: 0 / 0
Process finished with exit code 0

You’ll see that everything is looking good and everything is almost identical to what we did before, with one main difference. You’ll see a new line “A new player character has been created!” at the top of each section when a new instance is constructed.

That line is located in our PlayerCharacter class constructor. When we create a class that is built on top of another class, it will run the contents of the base class constructor and then the code in the class it is built on top of.

But if we try to do that with the showStats() method , the same behavior doesn’t happen. For example, change the PlayerCharacter showStats() method to add a new statement to the output console:
public class PlayerCharacter {
    // Name
    public String name;
    // Skill attributes
    public int strength;
    public int intelligence;
    public int agility;
    // Health and magic
    public int maxHitPoints;
    public int hitPoints;
    public int maxMana;
    public int mana;
    PlayerCharacter() {
        System.out.println("A new player character has been created!");
    }
    public void showStats() {
        System.out.println("Here are the stats for, " + name);
    }
}

If you run the program again, the code in the PlayerCharacter showStats() method is never displayed. When you build on top of a class and want to run code from a method it is built on top of, you need to specifically state you want to run it. A constructor will automatically run the code in the base class without you needing to do anything.

To call the code in a base class’ matching method, you need to use the super statement. Let’s update the Mage class to see how this works:
public class Mage extends PlayerCharacter {
    // Skill attributes
    public int wisdom;
    Mage(String newName) {
        // Constructor
        name = newName;
        strength = 7;
        intelligence = 15;
        agility = 8;
        wisdom = 10;
        strength += (int) (Math.random() * 6 + 1);
        intelligence += (int) (Math.random() * 6 + 1);
        agility += (int) (Math.random() * 6 + 1);
        wisdom += (int) (Math.random() * 6 + 1);
        maxHitPoints = hitPoints = strength;
        maxMana = mana = intelligence + (wisdom * 2);
        System.out.println("A new mage named " + name + " has been created!");
    }
    public void showStats() {
        super.showStats();
        System.out.println("””””””””””””””””””””””””””””””””””");
        System.out.println(name + ", a mage:");
        System.out.println("    Strength: " + strength);
        System.out.println("Intelligence: " + intelligence);
        System.out.println("     Agility: " + agility);
        System.out.println("      Wisdom: " + wisdom);
        System.out.println("  Hit Points: " + hitPoints + " / " + maxHitPoints);
        System.out.println("        Mana: " + mana + " / " + maxMana);
        System.out.println();
    }
}
You’ll see that the showStats() method has a call at the beginning:
super.showStats();
This will go to the class that this class extends and execute the method. If we run this program, we can see how this works:
A new player character has been created!
A new mage named Francisco has been created!
Here are the stats for, Francisco
””””””””””””””””””””””””””””””””””
Francisco, a mage:
    Strength: 13
Intelligence: 19
     Agility: 12
      Wisdom: 16
  Hit Points: 13 / 13
        Mana: 51 / 51
A new player character has been created!
A new mage named Jaana has been created!
Here are the stats for, Jaana
””””””””””””””””””””””””””””””””””
Jaana, a mage:
    Strength: 9
Intelligence: 18
     Agility: 12
      Wisdom: 15
  Hit Points: 9 / 9
        Mana: 48 / 48
A new player character has been created!
A new fighter named Dupre has been created!
””””””””””””””””””””””””””””””””””
Dupre, a fighter:
    Strength: 18
Intelligence: 8
     Agility: 13
Constitution: 16
  Hit Points: 68 / 68
        Mana: 0 / 0
A new player character has been created!
A new fighter named Sentri has been created!
””””””””””””””””””””””””””””””””””
Sentri, a fighter:
    Strength: 18
Intelligence: 9
     Agility: 9
Constitution: 13
  Hit Points: 62 / 62
        Mana: 0 / 0
Process finished with exit code 0

If you notice, only the mages that are created display the “Here are the stats for…” line. That is because we haven’t added the super.showStats() call to the Fighter class , only to the Mage class.

When you create classes like this that extend other classes, you are creating a class hierarchy. The base class is called the superclass. The class that you create that extends the superclass is called the subclass.

So, in our example, PlayerCharacter is the superclass. Mage and Fighter are subclasses of the PlayerCharacter superclass.

When we use the super statement, we are asking the superclass to do something, in this case, the PlayerCharacter class .

You can create as many subclasses of a superclass as you want, and you can continue to extend classes as far as you need to.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.143.31