Chapter:Classes - Defining constructors

From Juneday education
Jump to: navigation, search

Meta information about this chapter

Expand using link to the right to see the full content.

Introduction

This chapter, in the suite of chapters on classes, explains the role of, and how to write constructors, in a class. Constructors are of course a central part of a class definition (for such classes that serve as blueprints for objects). The students have already seen how to create objects using the new operator and the syntax which follows it. Here we explain what is going on when an object is created using new.

We explain that code which creates an object using new triggers the execution of a "constructor" in the class for the object, and what the corresponding code in the class looks like.

Purpose

The purpose of this chapter, is to focus on the definition of a constructor when writing a class, so that the student knows that classes may define constructors and, in which case they do, what the code for a constructor looks like.

Also, we want to take the opportunity to discuss the role of constructors, and how constructors can accept parameters to initialize an object's initial state.

Included in the knowledge about constructors is the meaning and use of the keyword this. Understanding and knowing the implications of the keyword this is central to the Java programming language. This also allows us to discuss scope, like when a parameter has the same name as an instance variable. And we want the students to know how to call a second constructor from a constructor, which is another use of this.

Having more than one constructor leads to the introduction of the concept of overloading, which we will return to in the chapters on methods.

Goal

After this chapter, the student shall understand:

  • What a constructor is
  • When a constructor's body is executed
  • How to write a constructor
    • How to use the keyword this when distinguishing an instance variable from a local variable (or parameter) with the same name, as well as when calling a constructor from a constructor
  • What overloaded constructors mean and what the need for more than one constructor comes from

Additionally, another goal for this lecture is to show a need for methods - the students have learned that constructors can initialize private instance variables, but what about accessing their value? Changing the value?

Instructions to the teacher

Common problems

  • Students might struggle with understanding how an instance variable can have the same name as a parameter and how to distinguish between the two
    • Spend some time to really let this sink in
  • Don't avoid talking about the keyword this by constantly having different names of the parameters versus the instance variables!
    • The keyword is there for a reason, and it is being used in code
    • The keyword is used also for calling constructors, we can't show only one of two uses of the keyword

For students who want a technical explanation of the keyword this, you may use the following explanation: An instance method operates on a specific object. In Java, you call an instance method via a reference to the object in question. It may look like this: myObject.someMethod(). How does the JVM know what object's instance method to execute? Imagine that the call to someMethod() always contain an implicit hidden argument, the reference. So what actually is going on is the equivalent of this pseudo code: someMethod(myObject) - the reference myObject is sent as a hidden parameter to the method. The method in turn, accepts this hidden parameter and calls the parameter this. The conclusion is, that the reference called this refers to the same object in the JVM's heap as the reference myObject, which was used to perform the call of the instance method.

The designers of Java decided that it would be more clean to use the syntax where we do someReference.someMethod(), that is, the reference followed by a dot and then the instance method name. Also, it makes for less code. If the reference is always passed as a parameter to all instance methods, then why not make it implicit? And call the parameter this? That's what the designers of Java went for.

When it comes to constructors, you may think of this like this: The operator new triggers the JVM to create space in the heap for an object of the named class, and return a reference to this object in the heap. The constructor's block is executed with a hidden, implicit parameter with the reference to the object in the memory. As with instance methods, that parameter is called this and is available in the block of the constructor.

For a not-so-technical explanation, use a whiteboard and illustrate code that calls a constructor via new and the constructor signature on one side of the whiteboard, for instance the left-hand side. On the right-hand side, draw the heap memory and the new object there. Below the heap illustration, draw the class with the constructor code. Draw arrows to the object from the reference being assigned the result of the call to new to the object in the heap, and draw arrows from the use of this in the constructor code to the same object.

Do the same with a call to an instance method.

_________________________________________________________________________
// Code calling an instance method | heap memory                         |
String nr = myPassport.number();   |                                     |
              \                    |                                     |
               `-------------------+----> (myPassport object) <-.        |
                                   |       nr = 1234             `.      |
                                   |                               |     |
                                   |                               |     |
                                   +-------------------------------+-----+
                                   |                               |     |
                                   | //Passport.java - class       |     |
                                   | public void validate() {      |     |
                                   |   return this.number;         ,     |
                                   | }          \_________________/      |
                                   |                                     |
-----------------------------------+-------------------------------------+

Classes: defining constructors

This section deals with constructors and the syntax and semantics involved. As constructors are one of the basic building blocks for (many) classes, it is important to learn and understand how to declare them.

The role of constructors is to define how objects can be created from the class. Constructors are run (the code in the constructor executes) when client code creates an instance from a class using the operator called new as we have seen in previous chapters. It is often in the constructor objects are given their initial state. It is common that a constructor declares parameters so that client code can pass the initial values for the initial state of the object.

To allow for flexibility, a class can declare more than one constructor where the constructors differ in the type and number of arguments which can be passed to the constructor. This can provide means to create objects passing along varying information to the initial state. To declare variations of constructors or methods in this way, is sometimes called overloading.

The class java.lang.String serves as an example. It declares many overloaded constructors, which gives us flexibility in how we can construct a String object. There is one constructor without any parameters at all which simply creates an "empty string". Then there is one constructor which takes a reference to another String object as the only parameter, which allows us to create a new String as a copy of some other existing String object. And then there's one constructor which takes a reference to an array of char as the argument, which allows us to create a String object representing the characters found in the array.

If we don't declare any constructors at all, the compiler will actually provide one for us (with no arguments). This is a kind of convenience feature, which allows us to create new objects (with no data provided for initial state) without having to write code for a constructor which seemingly does nothing in the body of the constructor. If we declare at least one constructor, the compiler won't, however, provide any constructor for us.

When we say that the compiler provides a constructor for us, it is important to know that the constructor will be inserted in the resulting class file from the source code file. The compiler will not ever insert any code in our source code files!

The syntax of a constructor is:

<access-modifier> ClassName(<parameter-list-if-any>) {
  <code-for-initialization>
}

Typically, the access modifier is the keyword public which means that the constructor is available in client code in any class in a program. It is common to have public constructors, since many classes exist for client code to create objects which they need to solve some task. As you will see in sections below, there are more access modifiers than public which limit what client code is allowed to use the constructor. The "ClassName" in the simplified syntax above, means that the constructors "have the same name" as the class. Alternatively you could think of the class name as the "type" created by the constructor. Regardless, it is a strict syntax rule that the constructor must have the class name before the parentheses around the parameter list.

The parameter list may be empty. If the constructor has parameters, which are placeholders for any values provided as arguments when creating a new object, they are a comma separated list of the form type variableName. Here's an example of a no-arguments constructor:

public Greeter(String greeting) {
  // do something with greeting
}

In the example above, we show a constructor for the class Greeter, with the access level public (the constructor can be used in code from any other class), and a parameter list of one single argument, a reference to a String which will be referred to in the body of the constructor as greeting. When you declare arguments, the arguments become local variables which may be used only in the body of the constructor (or method). Let's explain that with other words! The purpose of parameters is to allow for data to be passed from one place in a program (perhaps in the main method) to code in some other place (perhaps a constructor in a class in some package imported from main). The calling code "passes data as arguments" to, for instance, code for a constructor in another class. The code for the constructor must have a way to reference (talk about) the data sent to it. This is done by declaring parameters with a type and a name, like String greeting in the constructor example above. The parameter greeting will work like a variable local to the constructor code. It will get it's value when and if some other code calls the constructor using the operator new. A local variable, as we've discussed in previous chapters, is a variable that is known only in some block, and as a result only can be used in that block.

A closer look at the Greeter example. The purpose of a constructor, as the one above, is to give the object being created by the constructor, an initial state. This is often done via parameters whose values are stored in an instance variable for the class. See the section about instance variables for information on the syntax and semantics of instance variables. Let's say that an instance of class Greeter is capable of responding to the action (or message) greet(). The object could for instance play a sound with a greeting phrase or output some greeting to standard out. But where is this greeting phrase stored, and how does it get initialized?

An object typically stores the data it needs to accomplish some task in so called instance variables declared in the class. Typically, it is the role of the constructor to accept the initial value of the data via some parameter. The block of the constructor then uses the parameter name as a variable and assigns the value to some suitable instance variable.

In order for the code in the constructor to be able to refer to instance variables, Java uses the keyword this and a dot and then the name of some instance variable. Let's take a closer look at how the Greeter class could accomplish this:

public class Greeter {
  private String greeting; // instance variable to store this object's greeting phrase

  // Constructor accepting a String reference to some greeting text
  public Greeter(String greeting) {
    // store the parameter in the instance variable
    this.greeting = greeting;
  }
}

You may be surprised that the instance variable has the same name as the parameter. This would be very problematic if it wasn't for the keyword this! But using the keyword this, we have a way to refer to instance variables of the object being constructed by the constructor! You can read the code this.greeting out loud as "this object which is being constructed here has an instance variable called greeting". Now, the statement this.greeting = greeting; clearly (we hope) means that this object's instance variable "greeting" should be assigned the value of the parameter "greeting". Now, we also learn that when the name "greeting" is being used without the "this" keyword, it refers to the parameter.

One way to think about that is that when we use a name in some block of code, the name refers to the variable declared in the closest scope (or block). The parameter named "greeting" is declared in the constructor which must be the closest block/scope. The instance variable with the same name is declared in the enclosing block (the block of the class definition). So when we use the name "greeting" in the constructor, we mean the parameter. It is the "closest" variable declared with that name. If we want to use the instance variable with the same name, we had to use the "this" keyword since the instance variable is not declared in the closest scope.

Wouldn't choosing different names for the parameter and the instance variable solve all this without the need for the this keyword, you may ask. Of course, but this is a book about Java and the way Java works, so we don't want to give you the (false) idea that the parameter names must differ from the instance variables. In fact, we could use the this keyword anyway to refer to an instance variable with a different name. The this keyword always refers to "this object". Here's the same class with a different name of the parameter:

public class Greeter {
  private String greeting; // instance variable to store this object's greeting phrase

  // Constructor accepting a String reference to some greeting text
  public Greeter(String aGreeting) {
    // store the parameter in the instance variable
    this.greeting = aGreeting;
  }
}

Here, the parameter is called "aGreeting" and the instance variable is called "greeting". So we don't have to use the this keyword, but we can anyway. Using this, even though we don't have to, could help to make the code clear actually. Now that we told you, you know that this.greeting must refer to an instance variable. There are other uses of this but this is not the place to talk about those. The important part here is that this always means "this object".

Note that in all the examples above, we didn't include a package statement, to keep our code focused on the constructor. Normally it would be the first line of code in the source code file and precede the class declaration public class Greeter { . And, by all means, note that objects created from the stupid example class can't actually do anything with the greeting text, since we haven't written any methods with code that does something with the instance variable. The objects would only store some text but we could never access that text. We apologize for this.

Chapters about classes

Here are the chapters about classes in this book, so that you can keep a check on your progress:

Videos

Links

Further reading

Where to go next

Next page has exercises for this chapter: Classes_-_Defining_constructors_-_Exercises

« PreviousBook TOCNext »