Introduction

Java is an object-oriented language, so understanding what objects are and how to use them is crucial to using Java effectively. An object in OOP is a lot like an object in the real-world. In the real-world, the term “object” is very non-specific. An object can refer to basically anything, whether it’s a book, a planet, a receipt, a red blood cell, an engine, or a dog. These are all types of objects. These objects vary greatly in terms of their size, shape, colour, complexity, purpose, and so on.

Object’s are often composed of or associated with other objects, and these objects may communicate or interact with each other in various ways. For example, a car is made up of thousands of objects such as wheels, doors, windows, lights, seats, a radio, pedals, an engine, etc. When driving a car, various objects/components must interact in a certain way to move the car forward i.e. a human presses on the accelerator pedal, which delivers fuel into the engine, which turns the crankshaft, which powers the drivetrain, which turns the wheels. This chain of communication works because every object in the chain has been designed to interface with its connecting objects.

That is the sort of thing OOP tries to emulate–a number of separate but connected objects that interact to achieve a goal. Of course, OOP does not deal with real objects, but “virtual” objects that are defined and created by you, the programmer. These objects can take on any form, complexity, and responsibilities you see fit. You are limited only by your imagination. In practice, the types of objects you’ll deal with depends on the application you’re building.

State and Behaviour

Two key properties of both real and virtual objects are state and behaviour. Take a lamp, for example. A lamp can be on or off, which are two possible states. A lamp can also turn on and off, which are two behaviours. Typically, behaviour affects state. That is, turning on the lamp puts it in an on state and turning off the lamp puts it in an off state. You can think of state as data about an object, or as an object’s attributes. Here are some more examples of the lamp’s state:

  • brightness
  • hue (the emitted colour)
  • colour (the colour of the lamp itself)
  • height/width/length (physical dimensions of the lamp)
  • weight
  • timer duration (for an auto-off function)
  • time remaining on timer
  • power efficiency rating
  • heat output

The behaviour of an object is about what it can do. For example, the lamp can:

  • Increase/decrease brightness
  • Change hue
  • Turn timer on/off
  • Increase/decrease timer duration
  • Increase/decrease height (if extendable)

When it comes to OOP, we use variables to represent an object’s state and methods to represent an object’s behaviour.

  • State = Data = Variables
  • Behaviour = Actions = Methods

Example: Employee Objects

Some of the simplest objects you can define are record-like objects. For example, imagine a company that keeps files/records of all its employees but on paper only. Here are three of those files:

Employee File 1
Name: Michael Orwell
Address: 123 Indigo Rd.
DoB: 1993/11/20
Job Title: Project Manager
Salary: £41,093

Employee File 2
Name: Veronika O’Neill
Address: 789 Yorkminster St.
DoB: 1998/01/15
Job Title: Junior Developer
Salary: £23,476

Employee File 3
Name: Lester Wilcox
Address: 456 Lioborough Ln.
DoB: 1991/05/01
Job Title: Senior Developer
Salary: £35,950

Each file represents a different employee and contains relevant data about them. Let’s look at how we might replicate this in the OOP world.

  1. First, create a new Java project.
    1. If you’re on the welcome screen, click Create New Project.
    2. If you already have a project open, go to File > New > Project….
  2. Ensure Java is selected and click Next.
  3. Check Create project from template and click Next.
  4. Choose a project name (e.g. EmployeeManagementApp), project location, and package.
  5. Click Finish.

To start, we can take all the fields in the files and turn them into variables.

public class Main {
    public static void main(String[] args) {
        String name;
        String address;
        String dateOfBirth;
        String jobTitle;
        double salary;
    }
}

The first four are String types because they are textual data. While you could also make salary a String, I’ve decided to make it a double because it’s numeric data. There are more suitable types that could be applied but we’ll keep it simple for now. Currently, the variables have no values, so let’s set them to the values of a particular employee like this:

public class Main {
    public static void main(String[] args) {
        String name = “Michael Orwell”;
        String address = “123 Indigo Rd.”;
        String dateOfBirth =  “1993/11/20”;
        String jobTitle =  “Project Manager”;
        String salary = 41093;
    }
}

But what about the other employees? We could declare further sets of variables like name2, address2, dateOfBirth2, jobTitle2, and salary2, and then name3, address3, dateOfBirth3, etc, but we could have 100 employees to deal with so this clearly isn’t the way to go. The problem is we lack structure. It would be nice if we could bundle all this related data together and store it all under one name, like some sort of composite data type. The good news is you can, with objects.

Class: Employee

What we’ll do is create some objects to act as virtual records that perform the same job as the real records i.e. to represent employees in the company. Each object will contain the same set of fields (variables) but hold different data depending on the employee. But before we can do this, we need to write a class. A class defines a type of object, from which many of those objects can be created. You can think of a class as the design, and an object as the product. This is similar to the real-world where a design, such as a blueprint, can be used to construct an object, such as a house. The design may be used over and over again to construct as many houses as required. So, just like you need a house blueprint to construct house objects, you need an Employee class used to construct Employee objects.

Let’s create the Employee class. First, right-click the src folder and go to New > Java Class. Type Employee and hit Enter. It should look this:

public class Employee {

}

Note that when you define a class, you are also defining a new type. You already know of certain pre-existing types such as int, double, char, String, Scanner, etc. Employee is simply another type that can be added to that list. This means we can now create Employee objects and declare variables of type Employee to hold those objects. We create an Employee object the same way as any other object, by using the new keyword. Back in the main method, we can write this:

public class Main {
    public static void main(String[] args) {
        Employee emp = new Employee();
    }
}

On the left side is simply a variable called emp (short for “employee”), and it’s type is Employee (meaning it can hold an Employee object). The Employee object is created on the right side. However, if you look back at the Employee class, you’ll notice that it’s empty. That means any Employee objects (such as emp) will also be empty, which means these objects have no state (fields/variables) nor behaviours (methods).

Instance Variables

Let’s add the variables from before to the Employee class:

public class Employee {
    String name;
    String address;
    String dateOfBirth;
    String jobTitle;
    double salary;
}

Now that the Employee class has some variables, any Employee objects created from it will possess a copy of these variables. For this reason, they are known as object variables or instance variables (instance is another term for object). Therefore, emp has a copy of these variables, which we can access by using the . e.g. emp.name, emp.address, etc. With that in mind, let’s make emp represent employee Michael Orwell by assigning its variables the relevant values:

public class Main {
    public static void main(String[] args) {
    	Employee emp = new Employee();
    	emp.name = "Michael Orwell";
    	emp.address = "123 Indigo Rd.";
    	emp.dateOfBirth = "1993/11/20";
    	emp.jobTitle = "Project Manager";
    	emp.salary = 41093;
    }
}

Note: if you get errors, make sure both classes (Main and Employee) are in the same package.

Line 4 sets name to “Michael Orwell”, line 5 sets address to “123 Indigo Rd.”, line 6 sets dateOfBirth to “1993/11/20”, line 7 sets jobTitle to “Project Manager”, and line 8 sets salary to 41093. Wherever emp goes, all this data goes with it. Next, let’s print out some information about this employee:

public class Main {
    public static void main(String[] args) {
    	Employee emp = new Employee();
    	emp.name = "Michael Orwell";
    	emp.address = "123 Indigo Rd.";
    	emp.dateOfBirth = "1993/11/20";
    	emp.jobTitle = "Project Manager";
    	emp.salary = 41093;

        System.out.printf("The employee %s is a %s and earns £%.2f annually.\n", emp.name, emp.jobTitle, emp.salary);
    }
}
[Run]
The employee Michael Orwell is a Project Manager and earns £41093.00 annually.

Line 10 simply prints out a line of information using the variables of emp, specifically the employee’s name, job title, and salary. It is presented in a human-readable way.

Instantiating More Employee Objects

Let’s instantiate two more Employee objects the same way as the first.

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        emp1.name = "Michael Orwell";
        emp1.address = "123 Indigo Rd.";
        emp1.dateOfBirth = "1993/11/20";
        emp1.jobTitle = "Project Manager";
        emp1.salary = 41093;

        Employee emp2 = new Employee();
        emp2.name = "Veronika O'Neill";
        emp2.address = "789 Yorkminster St.";
        emp2.dateOfBirth = "1998/01/15";
        emp2.jobTitle = "Junior Developer";
        emp2.salary = 23476;

        Employee emp3 = new Employee();
        emp3.name = "Lester Wilcox";
        emp3.address = "456 Lioborough Ln.";
        emp3.dateOfBirth = "1991/05/01";
        emp3.jobTitle = "Senior Developer";
        emp3.salary = 35950;

        System.out.printf("The employee %s is a %s and earns £%.2f annually.\n", emp1.name, emp1.jobTitle, emp1.salary);
        System.out.printf("The employee %s is a %s and earns £%.2f annually.\n", emp2.name, emp2.jobTitle, emp2.salary);
        System.out.printf("The employee %s is a %s and earns £%.2f annually.\n", emp3.name, emp3.jobTitle, emp3.salary);
    }
}
[Run]
The employee Michael Orwell is a Project Manager and earns £41093.00 annually.
The employee Veronika O'Neill is a Junior Developer and earns £23476.00 annually.
The employee Lester Wilcox is a Senior Developer and earns £35950.00 annually.

Two more Employee objects have been created on lines 10 and 17. They are named emp2 and emp3. Both emp2 and emp3 have been filled with a particular employee’s data. I’ve also renamed emp to emp1 for consistency (line 3). Note that all three of these Employee instances (emp1, emp2, and emp3) are individual and distinct, and contain their own copy of the variables. Line 24, like before, prints out information about emp1. Line 25 does the same thing with emp2 and line 26 does the same thing with emp3. As we can see from the output, each object contains different data.

Instance Methods

Let’s give Employee objects the ability to do things by defining methods in the class. For example, instead of duplicating the same line to print information about each employee, let’s have the Employee objects do this themselves:

public class Employee {
    String name;
    String address;
    String dateOfBirth;
    String jobTitle;
    double salary;

    void printInfo() {
        System.out.printf("Employee %s is a %s and earns £%.2f annually.\n", name, jobTitle, salary);
    }
}

Employee now has a method called printInfo. It has a void return type because it doesn’t return any data. It’s parentheses are empty because it doesn’t require any data. In the body of this method is a print statement like the one’s in main. As you can see, it can access name, jobTitle, and salary directly. This is because methods are able to access the variables in the same class. Back in main, we can replace the three print statements with calls to said method:

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        emp1.name = "Michael Orwell";
        emp1.address = "123 Indigo Rd.";
        emp1.dateOfBirth = "1993/11/20";
        emp1.jobTitle = "Project Manager";
        emp1.salary = 41093;

        Employee emp2 = new Employee();
        emp2.name = "Veronika O'Neill";
        emp2.address = "789 Yorkminster St.";
        emp2.dateOfBirth = "1998/01/15";
        emp2.jobTitle = "Junior Developer";
        emp2.salary = 23476;

        Employee emp3 = new Employee();
        emp3.name = "Lester Wilcox";
        emp3.address = "456 Lioborough Ln.";
        emp3.dateOfBirth = "1991/05/01";
        emp3.jobTitle = "Senior Developer";
        emp3.salary = 35950;

        emp1.printInfo();
        emp2.printInfo();
        emp3.printInfo();
    }
}
[Run]
Employee Michael Orwell is a Project Manager and earns £41093.00 annually.
Employee Veronika O'Neill is a Junior Developer and earns £23476.00 annually.
Employee Lester Wilcox is a Senior Developer and earns £35950.00 annually.

Lines 24-26 call the printInfo method on all three objects. It may seem obvious, but when you call a method in an object, that method will act with respect to that particular object’s variables. For example, in emp1 we set name to “Michael Orwell”, jobTitle to “Project Manager”, etc. Therefore, calling emp1.printInfo() means that these variables/values will be used by the method. Similarly, emp2.printInfo() will work with emp2‘s variables, and emp3.printInfo() will work with emp3‘s variables.

With this change, the outcome is still the same but, now, if we want the informational message to change, we only have to change it in one place, the printInfo method, instead of potentially many places. For instance, lets have the method print out the information in a more professional manner.

public class Employee {
    String name;
    String address;
    String dateOfBirth;
    String jobTitle;
    double salary;

    void printInfo() {
        System.out.printf("Employee: %s | Address: %s | DoB: %s | Role: %s | Salary: £%.2f.\n", name, address, dateOfBirth, jobTitle, salary);
    }
}
Employee: Michael Orwell | Address: 123 Indigo Rd. | DoB: 1993/11/20 | Role: Project Manager | Salary: £41093.00.
Employee: Veronika O'Neill | Address: 789 Yorkminster St. | DoB: 1998/01/15 | Role: Junior Developer | Salary: £23476.00.
Employee: Lester Wilcox | Address: 456 Lioborough Ln. | DoB: 1991/05/01 | Role: Senior Developer | Salary: £35950.00.

Nothing major has changed here, just the way the information is presented.

References and the Object Heap

When you instantiate an object, it is placed in an area of memory called the heap. This is where all the objects in your program reside. Let’s use the Employee class from above as an example. In main, we can simply type new Employee();:

public class Main {
    public static void main(String[] args) {
        new Employee();
    }
}

This is a perfectly valid program. When it’s run, it will create an Employee object and place it on the heap, along with any other objects. Figure 11.3 depicts this.

Figure 11.1

As can be seen, the object contains the five variables as defined in the Employee class. The 0x01 is the memory address of the object, which represents its location in memory. Objects are destroyed when the program ends so this object would be destroyed immediately after creation.

Let’s now assign a variable to the object.

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
    }
}

The variable emp1 does not contain the Employee object directly, but rather a reference to it, as shown in Figure 11.4.

Figure 11.2

Figure 11.4 shows that emp1 references the object by storing its address (0x01). So, even though we may say “emp1 is/stores an Employee object”, what we really mean is “emp1 contains a reference to an Employee object”. You don’t have to be fully aware of the reference when interacting with the object because Java automatically fetches the object and performs the stated action. For example, in the code emp1.printInfo(), Java looks at the reference in emp1, finds the corresponding object, and invokes the printInfo() method on it. However, you do have to be aware of references when passing objects around the application, such as into different variables. For example, what happens when we create another Employee variable and set it to emp1?

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = emp1;
    }
}

On line 4, another variable emp2 is declared and set to emp1. But what does this do exactly? You might think that emp1‘s object is copied into emp2, so we end up with two identical Employee objects, one in emp1 and one in emp2. That’s not what happens. Object’s are never copied in this way. Java variables follow the pass-by-value rule, which means the variable’s value is copied i.e. the reference. So, the reference in emp1 (0x01) gets copied into emp2, and we end up with this:

Figure 11.3

The reference in emp1 is copied into emp2 so both variables reference the one and only object. This means you can interact with the object through either variable. Note that, in reality, we don’t know exactly what a reference looks like because its down to the implementation of the JVM (Java Virtual Machine). It may not be as simple as just the memory address of the object. Just know that a variable stores something that connects it to the object, which we call a reference.

An Un-Referenced Object

The following program contains two variables that each reference an object.

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
    }
}

Line 3 creates an Employee object, which is referenced by emp1. Line 4 creates another Employee object, which is referenced by emp2. Figure 11.5 shows this.

Figure 11.4

What happens if we reassign emp1 to emp2‘s object?

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
        emp1 = emp2;
    }
}

The reference in emp2 gets copied into emp1, which means emp1‘s original object no longer has a reference to it, as shown in Figure X.

Figure 11.5

When an object has no references, it is lost and you cannot regain it, which means we have an object sitting in memory taking up space and is no longer usable. This is an issue in older programming languages because you had to manually manage the memory yourself. You had to make sure you created and deleted objects appropriately lest you risk a memory leak (where disused objects are not properly disposed of and take up more and more memory). In modern languages such as Java, for the most part you don’t have to worry about this issue because of something called a garbage collector. This is a program that runs behind the scenes with your Java program. The garbage collector periodically checks for objects that have no references and automatically deletes them, freeing up the memory for other objects/entities.

Null Reference

If you do not want a variable to reference an object, you can set it to null at any point. For example:

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        emp1 = null;
    }
}

On line 3, emp1 has a reference to an Employee object, as shown in Figure 11-X:

Figure 11.6

On line 4, emp1 is set to null, which also clears the reference, as shown in Figure 11-X:

Figure 11.7

The object is now available for garbage collection.

Note that in all these examples, we have not been setting the objects’ variables i.e. name, address, etc. Object variables are given default values depending on their type. ints default to 0, doubles to 0.0, booleans to false, and Strings to null.

Primitive and Reference Types

All types in the Java language fall under one of two categories: primitive types and reference types. There are only eight primitive types in the Java language: byte, short, int, long, float, double, char, and boolean. Everything else is a reference type, such as Employee, Scanner, String, DecimalFormat, ArrayList, arrays, and the thousands of other types we’ve yet to explore. Most reference types are class types from which objects can be created. As covered in the last section, reference types are named as such because reference variables hold a reference to the object, not the object itself. Conversely, primitive variables simply hold their value. That’s really all there is to it.

An Array Of Objects

One of the most useful things you can do with these kinds of objects is put them in some sort collection for processing, such as an array. You can make an array out of any type, including user-defined types such as Employee. First let’s instantiate three Employee objects without using an array.

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
        Employee emp3 = new Employee();
    }
}

Lines 3-5 create three Employee objects: emp1, emp2, and emp3. This is what it currently looks like:

Figure 11.8 | Three variables containing references to three Employee objects.

Next, we can set the fields in each object:

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
        Employee emp3 = new Employee();

        emp1.name = "Michael Orwell";
        emp1.address = "123 Indigo Rd.";
        emp1.dateOfBirth = "1993/11/20";
        emp1.jobTitle = "Project Manager";
        emp1.salary = 41093;

        emp2.name = "Veronika O'Neill";
        emp2.address = "789 Yorkminster St.";
        emp2.dateOfBirth = "1998/01/15";
        emp2.jobTitle = "Junior Developer";
        emp2.salary = 23476;

        emp3.name = "Lester Wilcox";
        emp3.address = "456 Lioborough Ln.";
        emp3.dateOfBirth = "1991/05/01";
        emp3.jobTitle = "Senior Developer";
        emp3.salary = 35950;
    }
}

Lines 7-11 assigns values to the variables in emp1, lines 13-17 do the same for emp2, and lines 19-23 do the same for emp3. Next, let’s create an Employee array:

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
        Employee emp3 = new Employee();

        emp1.name = "Michael Orwell";
        emp1.address = "123 Indigo Rd.";
        emp1.dateOfBirth = "1993/11/20";
        emp1.jobTitle = "Project Manager";
        emp1.salary = 41093;

        emp2.name = "Veronika O'Neill";
        emp2.address = "789 Yorkminster St.";
        emp2.dateOfBirth = "1998/01/15";
        emp2.jobTitle = "Junior Developer";
        emp2.salary = 23476;

        emp3.name = "Lester Wilcox";
        emp3.address = "456 Lioborough Ln.";
        emp3.dateOfBirth = "1991/05/01";
        emp3.jobTitle = "Senior Developer";
        emp3.salary = 35950;

        Employee[] empArr = new Employee[3];
    }
}

Line 25 creates an Employee array called empArr with room for three Employee objects. We haven’t put any objects in the array so currently all its elements are null. Arrays are also objects and live on the heap, too, as shown here:

Figure 11.9

empArr, at the bottom-left, is a variable that holds a reference to the actual array. Again, the array is filled with null values by default. Knowing what the default value will be for a particular type is quite easy. The default value for ALL reference types is simply null. The default value for primitive types is basically 0 or some equivalent value.

Next, let’s assign the array elements to the Employee objects:

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
        Employee emp3 = new Employee();

        emp1.name = "Michael Orwell";
        emp1.address = "123 Indigo Rd.";
        emp1.dateOfBirth = "1993/11/20";
        emp1.jobTitle = "Project Manager";
        emp1.salary = 41093;

        emp2.name = "Veronika O'Neill";
        emp2.address = "789 Yorkminster St.";
        emp2.dateOfBirth = "1998/01/15";
        emp2.jobTitle = "Junior Developer";
        emp2.salary = 23476;

        emp3.name = "Lester Wilcox";
        emp3.address = "456 Lioborough Ln.";
        emp3.dateOfBirth = "1991/05/01";
        emp3.jobTitle = "Senior Developer";
        emp3.salary = 35950;

        Employee[] empArr = new Employee[3];
        empArr[0] = emp1;
        empArr[1] = emp2;
        empArr[2] = emp3;
    }
}

Line 26 assigns index 0 to emp1 in the array, meaning the reference is copied from emp1 to index 0. Line 27 does the same with emp2 (into index 1), and line 28 does the same with emp3 (into index 2). This is what we end up with:

Figure 11.10

As you can see, the variable empArr holds a reference to the array (0x04), which in turn holds references to the Employee objects (0x01, 0x02, 0x03). This means Java has to resolve two references when going through empArr (the array itself and then one of the objects). The variables emp1, emp2, emp3 still have their references, which means we have two ways to access each object. For example, if we wanted to modify the object at 0x03 we can do it through either emp3 or empArr[2], as they both reference that object. Specifically, if we wanted to change jobTitle to “Accountant”, we can do it either through emp3:

emp3.jobTitle = "Accountant";

or through empArr:

empArr[2].jobTitle = "Accountant"

Again, when going through empArr, Java needs to resolve two references. So, behind the scenes Java looks at the reference in empArr (0x04), finds the array, looks at the reference in index 2 (0x03), finds the object, and then sets jobTitle to “Accountant”. The same would be true if using an ArrayList. This isn’t a problem in terms of performance or anything like that but it’s just something to be aware of when moving objects about.

Using a Foreach Loop on the Array

We can loop through array empArr like any other, and process each element in turn. The following program prints out each employee’s details:

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee();
        Employee emp3 = new Employee();

        emp1.name = "Michael Orwell";
        emp1.address = "123 Indigo Rd.";
        emp1.dateOfBirth = "1993/11/20";
        emp1.jobTitle = "Project Manager";
        emp1.salary = 41093;

        emp2.name = "Veronika O'Neill";
        emp2.address = "789 Yorkminster St.";
        emp2.dateOfBirth = "1998/01/15";
        emp2.jobTitle = "Junior Developer";
        emp2.salary = 23476;

        emp3.name = "Lester Wilcox";
        emp3.address = "456 Lioborough Ln.";
        emp3.dateOfBirth = "1991/05/01";
        emp3.jobTitle = "Senior Developer";
        emp3.salary = 35950;

        Employee[] empArr = new Employee[3];
        empArr[0] = emp1;
        empArr[1] = emp2;
        empArr[2] = emp3;

        for (Employee e : empArr) {
            System.out.printf("The employee %s is a %s and earns £%.2f annually.\n", e.name, e.jobTitle, e.salary);
        }
    }
}

Line 29 is a foreach loop that prints out the details of every employee. You can read it as “for each Employee e in empArr, do line 30″. In other words, each time the loop repeats, e will reference the next object in the array. Line 30 uses e to print out some information about the employee currently referenced by e i.e. e.name, e.jobTitle, and e.salary. So, on the first iteration, e references the Employee object at index 0, and line 30 will print out their details. On the next iteration, e will contain the Employee object at index 1, therefore line 30 prints that object’s values. The next iteration, e will contain the Employee object at index 2 and line 30 will print that object’s values. This results in the output:

The employee Michael Orwell is a Project Manager and earns £41093.00 annually.
The employee Veronika O'Neill is a Junior Developer and earns £23476.00 annually.
The employee Lester Wilcox is a Senior Developer and earns £35950.00 annually.

Practical Use of Class Employee

At this point, you may be wondering how Employee fits into an actual application. Remember the GuestList program back in chapter 9? It allowed you to add and remove guests to and from a list. It used an ArrayList of String to store all the names of all the guests. Strings are fine when you only want to store one piece of data, like a name, but if you want to store more data about each guest, such as their address, phone number, the time they arrived, their dietary requirements, etc, then String is not very practical. When you have an aggregation of data, there is no single built-in type that fits the bill, so you have to roll out your own. This is what we’ve achieved with the Employee class, and because Employee is a type, we can create an ArrayList of Employee to store any and all Employee objects in one place. You’ll typically want to use ArrayLists instead of arrays to store collections of items as they are far more flexible and easier to use. This is how to create an ArrayList of Employee:

(1) ArrayList<Employee> employees declares a variable named employees, whose type is ArrayList (of Employee). The ArrayList is named “employees” (plural) because it’s for the purpose of holding many Employee objects. Other reasonable names are “emps”, “employeeList”, “empList”, etc.

(2) new ArrayList<>() is the instantiation of the ArrayList object. Notice that the angle-brackets are empty. In older versions of Java you would have to write “Employee” there, like this: new ArrayList<Employee>(), but newer versions of Java can infer the type from the context so you don’t have to specify that it’s an ArrayList of Employee. In other words, Java sees that the variable’s type is ArrayList of Employee, and reasonably assumes that we want it to reference an ArrayList of the same type. Therefore, we can just write new ArrayList<>() and Java will create an ArrayList of Employee implicitly.

Let’s look at a program that uses an ArrayList of Employee to store employee data. The program is very basic. It allows the user to do two things: add employees to the list and view employees currently in the list.

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Employee> employees = new ArrayList<>();

        while (true) {
            System.out.println("1 | Add Employee");
            System.out.println("2 | Display Employees");
            System.out.print("Option: ");
            int option = sc.nextInt();
            sc.nextLine();

            switch (option) {
                case 1: {
                    System.out.println();
                    System.out.println("- NEW EMPLOYEE -");
                    Employee emp = new Employee();
                    System.out.print("Name: ");
                    emp.name = sc.nextLine();
                    System.out.print("Address: ");
                    emp.address = sc.nextLine();
                    System.out.print("DoB: ");
                    emp.dateOfBirth = sc.nextLine();
                    System.out.print("Job Title: ");
                    emp.jobTitle = sc.nextLine();
                    System.out.print("Salary: ");
                    emp.salary = sc.nextDouble();
                    employees.add(emp);
                    break;
                }
                case 2: {
                    System.out.println();
                    if (employees.isEmpty()) {
                        System.out.println("No employee data found.");
                    }
                    else {
                        for (Employee emp : employees) {
                            emp.printInfo();
                        }
                    }
                    break;
                }
            }
            System.out.println();
        }
    }
}

Line 6 creates a Scanner. Remember that Scanner and Employee are fundamentally the same in that they are both classes. This means a new Scanner object gets placed on the heap and variable sc contains a reference to it. Line 7 creates the ArrayList of Employee (also placed on the heap with employees containing a reference to it). Line 9 is the start of a while loop that contains the core of the program. First, lines 10-11 display two menu items: “Add Employee” and “Display Employees”. Lines 12-13 obtain the user’s input into option. Line 14 consumes the \n that is left behind so it is not wrongly read by future Scanner calls. Line 16 is a switch statement that has two cases, one for each option.

If the user enters 2, then case 2 displays all the employees in the list. Although, it first checks if the list is empty on line 38 using the ArrayList‘s isEmpty method. This method returns true if the ArrayList is empty, false if it’s not. If it’s empty, line 39 prints “No employee data found.”. If it’s not empty, the else block prints all the employees in the ArrayList. It does this using a foreach loop.

If the user enters 1, case 1 asks for all the details about the employee to add to the list. First, line 19 prints a header simply to be informative. Line 20 creates a new Employee object called emp. Line 21 asks for the employee’s name. Line 22 uses sc.nextLine() to obtain this information from the user and sets the name variable in emp to it. Lines 23-30 do the same thing with the other four variables in emp. Finally, line 31 adds emp to employees. How does line 31 work exactly? Remember that emp is a local variable that is declared in the switch statement (line 20). (This means it no longer exists when the switch statement ends.) emp contains a reference the Employee object that is created on the same line. When line 31 is reached, we can see that emp is passed to the ArrayList‘s add method. Again, it’s the reference inside emp that gets passed to the method. The add method puts this reference in the first available slot in the ArrayList (index 0 since the ArrayList is empty initially). Therefore, the ArrayList contains a reference to the Employee. Here is a sample run of the program:

[Run]
1 | Add Employee
2 | Display Employees
Option: 2

No employee data found.

1 | Add Employee
2 | Display Employees
Option: 1

- NEW EMPLOYEE -
Name: Justine Oakley
Address: 49 Calmford Gardens
DoB: 12/09/1994
Job Title: Human Resources
Salary: 20105

1 | Add Employee
2 | Display Employees
Option: 2

Employee: Justine Oakley | Address: 49 Calmford Gardens | DoB: 12/09/1994 | Role: Human Resources | Salary: £20105.00.

1 | Add Employee
2 | Display Employees
Option: 1

- NEW EMPLOYEE -
Name: Rylan Tempest
Address: 2 Lemonzest Orchard
DoB: 30/01/2000
Job Title: Sales Representative
Salary: 23372

1 | Add Employee
2 | Display Employees
Option: 2

Employee: Justine Oakley | Address: 49 Calmford Gardens | DoB: 12/09/1994 | Role: Human Resources | Salary: £20105.00.
Employee: Rylan Tempest | Address: 2 Lemonzest Orchard | DoB: 30/01/2000 | Role: Sales Representative | Salary: £23372.00.

1 | Add Employee
2 | Display Employees
Option:

As we can see, the user first entered 2. In case 2, because employees is empty, the if statement on line 36 prints “No employee data found.” Next, the user enters 1. Case 1 creates an Employee object and fills the object with data inputted by the user. Finally, line 31 adds this new object it to the list. The user enters option 2 again and the foreach loop on line 40 loops through the list and calls every object’s printInfo method. There’s only one Employee in the list so only one line of data is printed. Then the user repeats the above steps by adding another employee to the list and then displaying the list again, which outputs both Employee‘s in the list.

Using the console isn’t the most pleasant way of interacting with a program. When you learn how to create a GUI (graphical user interface), an application of this nature will be much more enjoyable to use (and to program). There’s also the issue that when the application exits, we lose all the Employee objects and any data they carry. This is because objects are stored in memory, not permanent storage. When you learn about file manipulation and databases, you’ll be able to save and load this data so it is not lost between sessions.

Leave a Reply

Your email address will not be published. Required fields are marked *