var q1 = "This class is called Message. There are two ways you can tell what a class's name is: by the name of the file (Message.java) and by the identifier used in the class statement (public class Message)."; var q2 = "This class has 1 attribute. The attribute is called 'message' and it's a String."; var q3 = "This class has 1 method. The method is called displayMessage().";

Constructor Methods

Things To Do First

Things To Do Later

Review: OOP Concepts

Using your notes, your textbook, and the online notes (including links to sites like webopedia.com), define each of the following:

What attributes would a class called "Door" have? What methods would the Door class have?

On paper or in an editor, create a class plan for the Door class.

Recall the following class from a previous lesson:

public class Message {
	
    public String message;

    public void displayMessage() {
        System.out.println(message);
    }
}

As a review, answer the following questions:

  1. What is the name of the class? [answer]
  2. How many attributes does the class have? What are their names? [answer]
  3. How many methods does this class have? What are their names and data types? [answer]

This is a very simple class that performs a very simple task: displaying a message on the screen. You should recall that we required a Java program that instantiated the MyMessage class:

public class TestMessage {
    public static void main(String[] args) {

        Message msgHello = new Message();
        msgHello.message = "Hello, World!";
        msgHello.displayMessage();
    }
}

This presents output exactly like that in a program we also earlier in the course:

public class MyFirstProgram {

    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

It should be obvious that writing the message application as a procedural program is a lot less effort than writing it as an object-oriented program. However, most real-world applications are larger and more complex, and in those cases, writing them as object-oriented applications will prove to save a lot of time and code.

Constructor Methods

By now you should have a good understanding of what happens in a statement such as:

Scanner keys = new Scanner(System.in);

We're going to add to our understanding of this statement. The Scanner() on the right side of the assignment operator is actually a call to a special method called a "constructor method". If you are becoming familiar with using the parenthesis after a method, then this should make sense to you: Scanner() has parentheses, so it does look like it's a method name. However, for a method, the naming conventions are all wrong!

The naming conventions for a constructor method are a bit different from other methods. A constructor's name must match the class name exactly and of course, include a set of parentheses. For example, the Book class's constructor methods should be called Book(). Constructor methods execute whenever a new instance of a class is created. The constructor method is responsible for creating the object in memory and, in some cases, giving the instance variables their initial values.

So far we haven't created any constructor methods in our classes, so how come we can use a statement such as Message greeting = new Message(); to create a new instance of the Message class?

If you don't include a constructor method in your class, the Java compiler will automatically include the default constructor in the compiled bytecode. When you execute a statement like the one above, you are actually invoking this default constructor!

A constructor method, like other methods, can take arguments. Usually a programmer would write a constructor with parameter variables so that the class can be instantiated with default values for the instance variables. For example, a programmer might like to give a new Book a title and price right away instead of saying textBook.title = "Programming Logic"; and textbook.price = 59.99; They could do this by using a constructor that takes a string and a double-precision number as arguments:

Book logicBook = new Book("Programming Logic", 59.99);

For this to work, the Book class must have a constructor method that has a string parameter variable and a double-precision parameter variable. The constructor can then assign the parameter variable's values to the instance variables. There are some rules that constructor methods must follow:

So, if we wanted to create the constructor for Book that allowed a programmer to set the title and price as the book object was created, we would start off with a header such as:

public Book(String bookTitle, double bookPrice) {
    // rest of code here
}

Notice that we've followed all the rules - a public method, no return type, and the name matches the name of the class exactly. Also, we've included the double parameter variables that will contain the values we want to give to the instance variables.

The next step is to set the value of the instance variables to the parameter values:

public Book(String bookTitle, double bookPrice) {
    title = bookTitle;
    price = bookPrice;
}

Using the "this" Keyword

What if my constructor method's parameter variables were defined as:

public Book(String title, double price) { ... }

Would this compile? What about the statements inside the constructor? If we changed them, our constructor would be:

public Book(String title, double price) {
    title = title;
    price = price;
}

How does Java know when we're referring to the instance variable title and when we're referring to the parameter variable title?? In fact, the program will compile with this constructor, but it will no longer work properly. In the statement title = title;, the variable "title" will be referring to the parameter on both sides of the assignment operator. This means the title (and also price) instance variables won't get their proper values.

This doesn't mean you have to change the parameter variable names back. There's a way to let Java know that you want to refer to the instance variable and not another variable with the same name. You use the this keyword. For example, this.title refers to "this book object's title", as opposed to the parameter variable title. So, since we want to put the parameter variable value into the instance variable, it would be correct to say:

this.title = title;

In other words, "this object's title attribute gets the value in the title parameter." You can update your constructor method so that it now becomes:

public Book(String title, double price) {
    this.title = title;
    this.price = price;
}

So is it proper or improper to give your parameters the same names as your instance variables? It's a matter of preference, although it does make the javadocs easier to read (you'll learn to write javadocs in the next course).

Exercise

In the previous section you designed a Room class:

public class Room {
    public double length;
    public double width;

    public String getDimensions() {
        return length + " x " + width;
    }

    public double getArea() {
        double area = length * width;
        return area;
    }
}

Add a two-parameter constructor to the Room class that allows a programmer to instantiate a new Room object with an initial length and width. Modify your TestRoom program to try out the new constructor.

The Default Constructor

Create a second room in your test class by using the default constructor:

Room newRoom = new Room();

What happens when you compile this program? You should get the following error:

TestRoom.java:13: cannot find symbol
symbol  : constructor Room()
location: class Room
                Room r2 = new Room();
                          ^
1 error

Even though the arrow is pointing at "new", the problem is that Java doesn't recognize the constructor "Room()". It's telling you that it can't find a constructor in your class that takes no arguments. But didn't we say earlier that Java creates a default constructor for you? Yes, but this is only true when you compile a class with no constructors. Once you define a constructor in your class, Java will no longer create the default constructor for you automatically. This means that if your class needs a default constructor, you will need to add one.

Most of your classes will need a default constructor. The default constructor can be used to initialize your instance variables to default values. In addition, a programmer will often want to construct an object and set the instance variable values later. For this reason, you should always make sure you include a default constructor in your class.

For the Room class, let's say that if the programmer wants to create a room object without an initial length and width, we'll initialize the length and width to 0:

public Room() {
	length = 0;
	width = 0;
}

If you don't have any code you want to put into a default constructor, but you need one anyway, you can make a blank one:

public Book() { }

This is a perfectly normal practice, and you'll see it in many other code samples.

Method Overloading

In a previous session, you learned about Method Overloading. It is quite common to overload constructors in a class. This allows other programmers multiple ways of constructing instances of your class.

The rules of method overloading still apply:

  1. The methods must have the same name
    • This should not be a problem, since all constructors must always have the same name as the class.
  2. The methods must have the same return type
    • This is also not a problem, since constructor methods never have a return type.
  3. The methods must have different parameter listings
    • You are providing different ways of creating objects for your class. A programmer might want to construct an object with initial values for some of the attributes, all of the attributes, or none of the attributes. Therefore, your constructors will always have different parameter lists.

Exercises

[solutions]

Create each of the following classes based on the class diagram below (in UML, something that starts with a + is to be declared as public; if it starts with a - (minus), it is to be declared as private. We haven't talked about the private modifier yet, so for now we'll declare everything as public. Note that this will change for certain members as we learn more about OOP):

1.

Class: Circle
Data Members:
+ radius : double
Methods:
+ Circle()
+ Circle(radius : double)
+ calcArea() : double
+ calcCircumference() : double
+ toString() : String

The calcArea() and calcCircumference() methods calculate and return the area and circumference of the circle (Use Google if you need to find the formulas). The default constructor sets radius to a default value of 1. The toString() method returns a string representation of the circle in the form:

Circle: radius=x.x

(where x.x is the radius value, formatted to 1 decimal place)

2.

Class: Time
Data Members:
+ hours : int
+ minutes : int
+ seconds : int
Methods:
+ Time()
+ Time(hours : int, minutes : int, seconds : int)
+ calcTotalSeconds() : int
+ toString() : String

This class models a specific time stamp on a clock. The calcTotalSeconds() method calculates and returns the total number of seconds from midnight to the time represented by the time object (use the normal calculation for total number of seconds: hours * 3600 + minutes * 60 + seconds). The default constructor sets the time to midnight by setting each attribute to 0. The toString() method returns a string representation of the time object in the form:

hh:mm:ss

(where hh, mm, and ss are the values of hours, minutes and seconds in the time object, formatted to show exactly 2 digits)

3.

Class: Dice
Data Members:
+ firstDie : int
+ secondDie : int
Methods:
+ Dice()
+ tossDice() : void
+ sum() : int
+ toString() : String

The tossDice() method generates to random integers from 1 to 6 and places one in each instance variable. The sum method returns the sum of the two dice values. The default constructor tosses the dice so that they are initialized with a random set of values. The toString() method returns a string representation of the pair of die in the form:

x, y

(where x and y are the two instance variable values)

Test the dice class in a Main class: construct the dice and allow the user to play a dice game that is a variation on the classic dice game called "Chicago": A player rolls a pair of dice 11 times. In those 11 rolls, they must attempt to roll each value from 2 to 12. At the end of the 11 rolls, total up the successful rolls to get their score.

In each round, display the dice roll and the sum of that roll in parentheses. For example, if the user rolled a 4 and a 3, then the value 4, 3 (7) is displayed.

After all rounds are completed, display a list of results: List each value from 2 to 12 and whether or not the user managed to roll that value during their 11 rounds.

After displaying the results of the 11 rounds, display the total points earned.

The sample program interaction and output below can better demonstrate how the game works:

Starting the game!
Round 2...
6, 3 (9)
Round 3...
1, 5 (6)
Round 4...
4, 4 (8)
Round 5...
6, 1 (7)
Round 6...
3, 1 (4)
Round 7...
1, 1 (2)
Round 8...
4, 3 (7)
Round 9...
4, 4 (8)
Round 10...
3, 4 (7)
Round 11...
5, 5 (10)
Round 12...
5, 2 (7)

Your results: 
 2: yes
 3: no
 4: yes
 5: no
 6: yes
 7: yes
 8: yes
 9: yes
10: yes
11: no
12: no
Your total score: 46

Hint: use a boolean array to keep track of which values from 2 to 12 the player has already rolled. Each round, check to see if the array element corresponding to that round number is set to false: if so, then that number hasn't been rolled yet, so you can count it.