Lesson 3 - RollingDie in Java - Constructors and random numbers

Java OOP RollingDie in Java - Constructors and random numbers

In the previous lesson, First object-oriented app in Java - Hello object world, we programmed our first object-oriented application in Java. We are already able to create new classes, insert fields, methods with parameters and return values into them. Today, we're going to start working on an arena in which two warriors will battle against each other. The battle will be turn-based and one warrior will deduct health points from the other one based on his attack and on the other warrior's defense. Essentially, we'll be simulating a board game, so we'll add a "die" to our game so as to add a bit of randomness to the game. We're also going to learn to define custom constructors.

We'll start by creating a new project and naming it ArenaFight. We will also add a new class to our project and name it RollingDie. Let's think about the fields we'll have to add to our die in order for it to function according to our current needs. We should be able to choose the number of sides. Typically 6 or 10 sides as is standard in this type of game. Our die will also need a random number generator. Java provides one for us, which includes the Random class for these sort of projects. In order to be able to use it, we need to import java.util.Random. We write imports at the beginning of the file, we know this since we've already imported the Scanner. Our class will now have two fields:

  • sidesCount of the int type
  • random of the Random type, where the random number generator will be stored.

Last time, for simplicity's sake, we set all the fields of our class as publicly accessible; however, in most cases, we don't want our fields to be modified externally. In this case, we will use the private modifier. A field is from then on only accessible from the inside of the class and from the outside Java treats it like it doesn't exist. When we design a class we usually set everything to private and then we make public only those class members we really need to expose. Our class should now look something like this:

import java.util.Random;

/** Class representing a die for a board game */
public class RollingDie {
        /** Random number generator */
        private Random random;
        /** Number of sides that the die has */
        private int sidesCount;

}

Сonstructors

We would now only be able to set the value of the public fields from outside of the class since the private fields are not visible from the outside. Next, we will go over constructors. A constructor is a method that is called while an object instance is being created. It sets the internal state of the object and performs any necessary initializations. We'd create a die in the ArenaFight.java now like this:

RollingDie die = new RollingDie();

The RollingDie() method is the constructor. Since our class doesn't have a constructor, Java automatically generated an empty method. However, we will now add a constructor to the class. We declare it as a method, but it doesn't have a return type. Also, the constructor must have the same name as the class name, which in our case is RollingDie (starting with the upper case letter unlike all the other methods). In the constructor, we'll set a number of sides to a fixed value and create an instance of the Random class. The constructor will look like this:

public RollingDie() {
        sidesCount = 6;
        random = new Random();
}

If we create the die now, it'll have a sidesCount field set to 6 and a Random class instance will be stored in the random field. We'll print the number of sides to the console, so as to visually confirm that the value is there. It's not good to set the field as public since we don't want to be able to change the number of sides once the die is created. We'll add a getSidesCount() method to the class which returns the value of the sidesCount field. We have now successfully created a read-only field. Meaning that, the field is not visible and can only be read only by using the "getSidesCount()" method, so it can't be changed from outside the class. The new method would look something like this:

/**
 * Returns the number of sides the die has
 * @return  Number of sides the die has
 */
public int getSidesCount() {
        return sidesCount;
}

Let's move on to ArenaFight.java so we could create our first die and print the number of its sides to the console:

RollingDie die = new RollingDie(); // the constructor is called right here
System.out.println(die.getSidesCount());

The output:

Console application
6

Now we have visual confirmation that the constructor had been called, but we still need to be able to specify how many sides our die will have. Let's add a parameter to our constructor:

public RollingDie(int aSidesCount) {
        sidesCount = aSidesCount;
        random = new Random();
}

Notice that we prefixed the parameter name with "a", otherwise it would have the same name as a field and cause an error. Let's go back to ArenaFight.java and add a value for this parameter in the constructor:

RollingDie die = new RollingDie(10); // a constructor with a par. 10 is called
System.out.println(die.getSidesCount());

The output:

Console application
10

Everything works as expected. Java will not generate an empty, aka parameterless, constructor, so we can't create a die without passing the parameter(s) it needs. We can, however, create another constructor, one that is parameterless. We'll set the number of sides to 6 since the user probably expects this value as default:

public RollingDie() {
        sidesCount = 6;
        random = new Random();
}

Let's create 2 dice instances now, one with a parameter and one without (in ArenaFight.java):

RollingDie sixSided = new RollingDie();
RollingDie tenSided = new RollingDie(10);
System.out.println(sixSided.getSidesCount());
System.out.println(tenSided.getSidesCount());

The output:

Console application
6 10

Java doesn't mind us having two methods with the same name as long as their parameters are different. Meaning that the RollingDie() method, which in this case is the constructor, is overloaded. This is a fact for all methods, not just constructors. NetBeans offers overloaded versions of methods when we're typing them. We can scroll through method variants with the arrow keys. We can see our two constructor overloads on the list:

IntelliSense hints for overloaded methods in Java

Many methods in Java libraries have several overloads. Take a look at the indexOf() method on the String class. It's good to look through function overloads, so you don't end up programming something what has already been done for you.

Now, let's go over how to name constructor parameters, in our case aSidesCount. If we were to write them out like this, we would make a mistake:

public RollingDie(int sidesCount) {
        sidesCount = sidesCount;
        random = new Random();
}

Java can't tell the two apart. In this case, the parameter is assigned to the parameter again. We can refer to the current instance inside a class because it is stored in the this variable. A practical use of the this variable would be to use it in a giveToPlayer(Player player) method and have it call a player.pickUp­Die(this) inside the instance. We'd essentially be passing itself, the concrete die instance with which we're working, to the other player by means of the this keyword. We won't deal with any of the "player" stuff for now, but we will set things up to reference the current instance while setting fields:

public RollingDie(int sidesCount) {
        this.sidesCount = sidesCount;
        random = new Random();
}

Using this, we specified that the left variable, sidesCount, belongs to the instance. The right one is treated as a parameter by Java. Meaning that we now have two constructors that allow us to create different dice.

Random numbers

Next, we'll define the roll() method in the RollingDie class, which will return a random number from 1 to the number of sides. The method will be public, meaning that it can be called from outside the class, and will have no parameters. The return value will be of the int type. We can obtain a random number by calling the nextInt() method on the generator. It has several overloads:

  • nextInt(): The Parameterless variant returns a random number in the entire range of the int data type.
  • nextInt(To): Returns a non-negative number lesser than the To bound. random.nextInt(100) therefore returns a number between 0 and 99.

The second overload suits our purposes the most, so we'll write:

/**
 * Rolls a die
 * @return A number from 1 to sides count
 */
public int roll() {
        return random.nextInt(sidesCount) + 1;
}

Do not create a random number generator in the method returning the random number. It would create a new generator for every random number and would result in the numbers hardly ever being random if at all. Always create a single shared instance of the generator, e.g. as a private field using the constructor, and then call the nextInt() method on it.

Overriding the toString() method

Our RollingDie class is almost ready, let's add one more method before we wrap up this class. The toString() method that we've briefly gone over in previous lessons is contained in every object, including our die. The method is designed to return a textual representation of the instance. Which is handy in all cases where we need to print the instance or work with it as if it were text. Even numerical datatypes have this method.

We already know that Java performs implicit conversions. When we want to print an object to the console, Java calls the toString() method and prints its return value. We should never make our own method such as print() when there is already a way to handle string conversions in Java. It makes no sense to use it in our die, but when implementing warriors it could return his/her names. Still, for education's sake, we'll override toString() in our RollingDie class anyway. It'll say that it is a die and print how many sides it has. First, print a RollingDie instance directly into our console:

System.out.println(sixSided);

Only the path to our class is printed to the console, which is ArenaFight.Ro­llingDie and it's followed by the instance hash.

We can't just declare a custom toString() method since it's already there (we'll find out why in an upcoming tutorial). We must override it. We won't go too far in detail for now, but I want you to know what the proper usage of toString() is. We use the Override annotation to mark overriden methods:

/**
 * Returns a textual representation of our die
 * @return  Textual representation of the die
 */
@Override
public String toString() {
        return "Rolling die with " + sidesCount + " sides";
}

Let's print out the die instance to the console again.

The output:

Console application
Rolling die with 6 sides

Let's test our rolling a die out now. We'll roll them in loops and see if they work as expected:

// Create instances
RollingDie sixSided = new RollingDie();
RollingDie tenSided = new RollingDie(10);

// Rolls the 6-sided die
System.out.println(sixSided);
for (int i = 0; i < 10; i++) {
        System.out.print(sixSided.roll() + " ");
}

// Rolls the 10-sided die
System.out.println("\n\n" + tenSided);
for (int i = 0; i < 10; i++) {
        System.out.print(tenSided.roll() + " ");
}

The output should look something like this:

Console application
Rolling die with 6 sides 3 6 6 1 6 3 6 2 6 3 Rolling die with 10 sides 5 9 9 2 10 4 9 3 10 5

We've created a nice, customizable class that represents a rolling die. It will come in handy when we get to the arena part of the application, but you can use it whenever you'd like. Hopefully, you now understand how OOP allows you to reuse components. In the next lesson, Reference and value data types in Java, we'll talk about the differences between reference data types (objects) and value data types (e.g. int). :)


 

  Activities (3)

Article has been written for you by David Capka
Avatar
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn College Author learned IT at the Unicorn College - prestigious college providing IT and economical education.

Do you like this article?
Total (1 votes) :
333 33


 



 

 

Comments

Avatar
Alabi Olaniyi Samuel:16. March 17:35

Which editor can I use to write this codes
-
-
-

 
Reply 16. March 17:35
Avatar
David Capka
ICT.social team
Avatar
Replies to Alabi Olaniyi Samuel
David Capka:17. March 3:58

We use NetBeans, it's shown in the first Java lessons - https://www.ict.social/…-application

 
Reply 17. March 3:58
To maintain quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it is free.

2 messages from 2 displayed.