Chapter 1 - Java for Beginners Course

Object Examples - Creating instances

In the previous section, we showed an example of an Airplane class in Java and how we can define the class name, its fields (state) and methods (behavior).

However, no objects from that class were created in that example.

The new keyword

There are different ways to create an instance of a class, the most standard one being the use of the new keyword in Java. This keyword asks Java to reserve memory for a new instance of a particular class and creates the requested object.

In its simplest form, for our Airplane example, to create a new instance of that class, all we need to do is invoke new Airplane().

Example 1

Airplane plane1 = new Airplane();

In this example, we can see three main actions taking place:

  1. The creation and initialization of a new Airplane object (the new Airplane() part).

  2. The declaration of a new variable called plane1 of type Airplane (the Airplane plane1 part).

  3. The assignment of the new object to the plane1 reference that was defined (the = that connects the 2 parts above).

Visually, if we assume the application memory was empty before executing the line above, we can think of our memory as an empty area that Java will start filling as we create objects, and at a high level we can see it as follows:

Memory Example 1

Objects vs References

It is important to make a distinction between a reference to an object and an object.

In our example above, plane1 is a reference to an instance of class Airplane, but plane1 isn’t an Airplane object as such.

An object reference points to an object of the declared type. As seen in the figure above, plane1 is pointing to the 'Airplane Object 1' that was created by the new Airplane() statement.

So, in this case, we have one Airplane object and one reference of type Airplane called plane1.

Let’s make a few simple modifications to our example code to help clarify the difference with the examples below.

Example 2

Airplane plane1 = new Airplane();
Airplane plane2;

In this case, there is still only one Airplane object being created (via the new Airplane() statement), but two object references, plane1 and plane2. In this example, plane2 isn’t pointing to anything, and we could represent it like this:

Memory Example 2

Example 3

Airplane plane1 = new Airplane();
Airplane plane2;
plane2 = plane1;
System.out.println("plane1 is pointing to the same instance as plane2: " + (plane1 == plane2));
The == operator in the last line is used to compare 2 variables in Java. When used with object references, it will return true if the two references are pointing to the same object, or false otherwise. In this case plane1 == plane2 is true as both point to the same Airplane object.

Output:

plane1 is pointing to the same instance as plane2: true

Similar to the previous example, one object and two references. However, in this case, we are changing the plane2 reference to point to the same object that plane1 is pointing to.

If we represented this visually, we could think about it like this:

Memory Example 3

Example 4

Airplane plane1 = new Airplane();
Airplane plane2 = plane1;
Airplane plane3 = new Airplane();
System.out.println("plane1 is pointing to the same instance as plane2: " + (plane1 == plane2));
System.out.println("plane1 is pointing to the same instance as plane3: " + (plane1 == plane3));

Output:

plane1 is pointing to the same instance as plane2: true
plane1 is pointing to the same instance as plane3: false

Here, we now have two calls to new Airplane() which will result in two different objects being allocated in memory. However, we have 3 references of type Airplane, namely, plane1, plane2, and plane3.

In the code, we are making plane2 point to the same object as plane1, and plane3 points to the second object that was created.

Or, visually:

Memory Example 4
This differentiation between objects and references is important to get right and it will become even more relevant later when we talk about memory management and garbage collection, and also when we introduce the concept of a null reference.

Null reference

Now that we understand that an object and an object reference are different, it is important to note that object references can have a special value called null.

This value represents that the object reference isn’t pointing to an object. null as a value has no memory representation (there is no actual object).

For example:

Airplane plane = null;

System.out.println("The plane is: " + plane);

plane.land();

System.out.println("End of program");

Output:

The plane is: null
Exception in thread "main" java.lang.NullPointerException
	at NullExampleApplication.main(NullExampleApplication.java:15)

Here, we are telling Java that our plane reference will be null, this means that no Airplane object is associated with it.

Invoking methods or accessing fields on null references

When we then try to invoke a method on that reference, plane.land() in our example, Java will throw an exception, indicating that it cannot operate over a null reference (there is no object that Java can use in this case). The same will occur if we try to access a field when having a null object reference.

We’ll cover the basics of exceptions in Chapter 3, however, they are events that disrupt the normal execution of our application. In our case, the exception that is thrown by Java is called a NullPointerException, indicating that we tried to perform an operation on a null reference.

In our output, this exception is what causes the application to print out: "Exception in thread "main" java.lang.NullPointerException…​"

You can see that the last line of the code System.out.println("End of program"); wasn’t executed due to the exception (it disrupted the normal application flow and in our case exited the main method at the point of the exception).

Null references and NullPointerExceptions (a.k.a NPEs) or their equivalent in other languages are called the "billion-dollar mistake" as they are the cause of several application errors/crashes and vulnerabilities. See https://en.wikipedia.org/wiki/Tony_Hoare for more details.
We’ll cover exceptions in more detail later, how to handle them and what options we have at hand when they occur.