Java Classes And Objects

Classes and Objects are the basic building blocks of a Java applications. Classes and objects are also the basic building blocks of object orientated programming.

In this tutorial we’ll look at classes and objects in Java. Moreover, we’ll look at the difference between classes and objects.

The basic idea between classes and objects, is that a class is used to create objects. Think of it this way, in object orientated programming we model the problem in software using objects, which are representations of the real world.

If we were modeling people, we may have a number of Person objects, where each Person object represents a unique person. Moreover, each person has a unique social security number, name, date of birth etc.

However, we need a place to store the code in our programs that can be reused and shared between objects. We can think of a class as a programming tool, that provides us with a place to store code, and give an identifiable name, thus simplfiying our life as a Java programmer.

Classes

A Java class represents the definition of an Object. It contains the code required to create objects. In particular it contains members: fields, constructors, and methods.

Let’s look at an example of using a class to represent a Person.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Person {
    private String socialSecurityNumber;
    private LocalDate dateOfBirth;
    private String firstName;
    private String lastName;

    public Person(String socialSecurityNumber, LocalDate dateOfBirth, String firstName, String lastName){
        this.socialSecurityNumber = socialSecurityNumber;
        this.dateOfBirth = dateOfBirth;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public void changeName(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    . . . . . . 
}

Above we show part of the class definition of a Person. In general a class normally contains fields that hold the state of the object.

1
2
3
4
private String socialSecurityNumber;
private LocalDate dateOfBirth;
private String firstName;
private String lastName;

These fields are known as instance variables. They define characteristics of a Person. If you think of Person in the real world, you can see that the fields closely match some of a Person’s characteristics.

Another important class construct is the constructor:

1
2
3
4
5
6
public Person(String socialSecurityNumber, LocalDate dateOfBirth, String firstName, String lastName){
    this.socialSecurityNumber = socialSecurityNumber;
    this.dateOfBirth = dateOfBirth;
    this.firstName = firstName;
    this.lastName = lastName;
}

The constructor is used to create an Object of a class, as we’ll see later. The constructor is used for instantiation and initialization. A constructor can take parameters that are used to initialize an object. Above, the constructor receives the parameters:

  • socialSecurityNumber
  • dateOfBirth
  • firstName
  • lastName

These parameters are used in the above example to give the fields of an object their initial value.

Moreover, every class contains a default constructor:

1
2
3
public Person() {

}

which takes no parameters. If we don’t provide a constructor, the Java compiler will create one for us. This is because to create an object from a class, a constructor is required.

Again, the job of the constructor is to initialize an object of a class. If a default constructor is used to create an object, then all fields will be set to default values.

You can read more about the different types of variables in the the tutorial Variables In Java.

So, we said a class contains fields that define the characteristics / state of an object. Also, a class has a constructor that is used to initialize and create an object from a class.

Moreover, a class in Java also contains another important construct called a method. Methods are used to define functionality / responsibilities that a class performs.

For example, in the above Person class we created a method changeName:

1
2
3
4
public void changeName(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

The above method provides the responsibility of allowing a Person to change it’s name.

Now that we looked at how to create a class, with state(fields), and behavior(methods), let’s examine the other important concept of objects.

Objects

As we mentioned classes are used to create objects. Whereas classes are normally, a compile time structure, objects are created at runtime during program execution.

Objects of a class are known as instances, and are created by calling the constructor of a class.

Object Instantiation

Creating an object from a class is commonly known as object instantiation. Instantiation is performed with the new keyword and a class constructor.

1
Person person = new Person();

Above we call the Person’s class default constructor. This creates an instance of the class Person and assigns it to the variable person. The person class holds the address in memory of where the object is held.

For more information about reference types see the tutorial Java Primitive Versus Object Types

Moreover, when we create an instance of an object from a class. It creates a unique instance of an object in memory.

This object contains a unique copy of its fields, whereas the objects methods are shared across object instances.

We can also create an instance of an Object by calling a custom constructor.

1
2
Person person = new Person("0000000001",
        LocalDate.of(1990, 04,12), "John", "Doe");

Above, we call the Person class constructor, passing values, for:

  • social security number
  • date of birth
  • first name
  • last name

These values will then initialize the fields of the Person object.

1
2
3
4
5
6
7
8
9
@Test
public void instantiatePerson() {
    Person person = new Person("0000000001",
            LocalDate.of(1990, 04,12), "John", "Doe");
    assertEquals("0000000001", person.getSocialSecurityNumber());
    assertEquals("1990-04-12", person.getDateOfBirth().toString());
    assertEquals("John", person.getFirstName());
    assertEquals("Doe", person.getLastName());
}

When we create an instance of an object from a class, it creates a unique instance.

1
2
3
4
5
6
Person johnDoe = new Person("1", "0000000001",
        LocalDate.of(1990, 04, 12), "John", "Doe");
Person janeDoe = new Person("2", "0000000002",
        LocalDate.of(1989, 04, 12), "Jane", "Doe");
Person mark = new Person("3", "0000000003",
        LocalDate.of(1985, 06, 15), "Mark", "Marks");

Above we create three unique instances of the Person class. Each instance is held in a distinct memory location.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Test
public void objectInstancesAreUnique() {
    Person johnDoe = new Person("1", "0000000001",
            LocalDate.of(1990, 04, 12), "John", "Doe");
    Person janeDoe = new Person("2", "0000000002",
            LocalDate.of(1989, 04, 12), "Jane", "Doe");
    Person mark = new Person("3", "0000000003",
            LocalDate.of(1985, 06, 15), "Mark", "Marks");
    assertFalse(johnDoe == janeDoe);
    assertFalse(janeDoe == mark);
    assertFalse(johnDoe == mark);
}

Object Methods

As we said an Object’s methods facilitates the behavior that an object provides. Just like a field, and constructor, an objects method is also known as a member.

We can access members of an object that are exposed in a given context using the dot notation:

1
<OBJECT_VARIABLE>.<MEMBER>

Therefore, we can call the method on a person object instance by:

1
2
3
4
Person johnDoe = new Person("1", "0000000001",
        LocalDate.of(1990, 04, 12), "John", "Doe");

johnDoe.getFirstName();

Above we call the getFirstName method to retrieve a persons first name. Some methods also accept parameters, for example lets say our John Doe has being identified.

1
johnDoe.changeName("Jason", "Bourne");

Calling the changeName method updates the person’s name, changing the objects state.

1
2
3
4
5
6
7
8
9
@Test
public void callMethod() {
    Person johnDoe = new Person("1", "0000000001",
            LocalDate.of(1990, 04, 12), "John", "Doe");
    assertEquals("John", johnDoe.getFirstName());
    johnDoe.changeName("Jason", "Bourne");
    assertEquals("Jason", johnDoe.getFirstName());
    assertEquals("Bourne", johnDoe.getLastName());
}

This Pointer

Another important concept when working with objects in Java, is the this pointer. Essentially, the this pointer, is used to reference the object itself.

This is a useful, operator when programming Java classes. It enables us to reference the current instance of an object. Therefore, we can use the this pointer inside of a non static block of a class, to reference members: such as fields, constructors and methods.

1
2
3
4
public void changeName(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

Above, we access the member fields: firstName, and lastName, using the this pointer. In this particular case we use the this pointer to change the persons name.

The this pointer can also be used to call methods on the object instance. For example we could rewrite the changeName method.

1
2
3
4
public void changeName(String firstName, String lastName) {
    this.setFirstName(firstName);
    this.setLastName(lastName);
}

Above, we use the this pointer to access the instance methods of the class.

We mentioned that we can access members of a class that are exposed from client code using the dot notation.

Let’s now examine what we mean by exposed.

Access Modifiers

Access modifiers control from what context classes, and members, can be accessed.

In general we have the following access modifiers in Java.

  • public
  • private
  • protected
  • package protected

Public

The public access modifier is the least restrictive. Public classes and members are accessible from everywhere. For example we defined our class with the public access modifier.

1
2
3
public class Person {

}

This means that instances of our class can be created from anywhere, once the class can be found on the Java classpath and loaded by a Java Classloader.

Moreover, we define a number of methods in our Person class as public. Therefore, these methods are accessible everywhere from an object instance.

1
johnDoe.changeName("Jason", "Bourne");

Private

The private access modifier is the most restrictive. Private members are not accessible from outside of the class. In our Person class we defined the fields as private.

1
2
3
4
5
6
7
public class Person {
    private String id;
    private String socialSecurityNumber;
    private LocalDate dateOfBirth;
    private String firstName;
    private String lastName;
}

Therefore, trying to access private members, from an object instance results in a compile time error.

1
johnDoe.firstName; //compile error

Note, it is common to define fields of a class as private, and only provide access to these fields via getter and / or setter methods. This is an Object Orientation technique known as encapsulation. Basically, encapsulation helps us to create more maintainable code, which can help to reduce bugs.

1
2
3
4
5
6
7
public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

The private modifier can also be applied to other members of a class, such as methods, and constructors.

For example if we define our class with only private constructors.

1
2
3
4
class Person {
    private Person() {
    }
}

Clients of our class would not be able to directly create instances of our class. Although, it would still be possible through the Java reflection API, to access and call private members, if the Java security manager permits it.

Protected

Although, not used in our Person example. The protected access modifier simply means a class or member is accessible inside of the same Java package or from a subclass from any package.

For example if we define the firstName field as protected:

1
protected String firstName;

It would be accessible from any subclass or any client code in the same package, via an object instance.

1
System.out.println(johnDoe.firstName);

Package Protected

Finally, the package protected access is enforced when we don’t explicitly, set an access modifier. We can use this access modifier with classes and members.

For example if we defined our Person class as:

1
2
3
class Person {
   public Person() { }
}

It would have package protected access and only be accessible inside of the package in which it is defined. This is an approach that can be used to not expose types that a client should not know about. We can think of package protected as code that is kept internal to a package.

The main difference between, protected and package protected is that protected allows us to use inheritance to access protected members from any package. Whereas, package protected restricts accessibility through extension to the same package.

Conclusion

In this tutorial we examined classes and objects in Java. We explained how classes and objects are the building blocks of Java programs. We also explained the difference between classes and objects. Finally, we looked at assigning access modifiers to classes and class members.