Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

All About Java Modifier Keywords

TwitterFacebookRedditLinkedInHacker News

I’ve been a Java programmer for a while now, however, recently someone asked me a question regarding one of Java modifier keywords and I had no clue what it was. This made it obvious to me that I needed to brush up on some Java that goes beyond actual coding and algorithms.

After a few Google searches, I got bits and pieces on the topic, but never really the full story, so I’m using this post as a way to document the subject. This is a great interview question to test your computer science book-smarts.

Modifiers in Java are keywords that you add to variables, classes, and methods in order to change their meaning. They can be broken into two groups:

  1. Access control modifiers
  2. Non-access modifiers

Let’s first take a look at the access control modifiers and see some code examples on how to use them.

ModifierDescription
publicVisible to the world
privateVisible to the class
protectedVisible to the package and all subclasses

So how do you use these three access control modifiers? Let’s take the following two classes. Please ignore how inefficient they may or may not be as that is besides the point for this tutorial.

Create a file called project/mypackage/Person.java and add the following code:

package mypackage;

class Person {

    private String firstname;
    private String lastname;

    protected void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    protected void setLastname(String lastname) {
        this.lastname = lastname;
    }

    protected String getFirstname() {
        return this.firstname;
    }

    protected String getLastname() {
        return this.lastname;
    }

}

The above Person class is going to have private variables and protected methods. This means that the variables will only be accessible from the class and the methods will only be accessible from the mypackage package.

Next create a file called project/mypackage/Company.java and add the following code:

package mypackage;

import java.util.*;

public class Company {

    private ArrayList<Person> people;

    public Company() {
        this.people = new ArrayList<Person>();
    }

    public void addPerson(String firstname, String lastname) {
        Person p = new Person();
        p.setFirstname(firstname);
        p.setLastname(lastname);
        this.people.add(p);
    }

    public void printPeople() {
        for(int i = 0; i < this.people.size(); i++) {
            System.out.println(this.people.get(i).getFirstname() + " " + this.people.get(i).getLastname());
        }
    }

}

The above class is public, so it can be accessed from any future classes inside and outside of the package. It has a private variable that is only accessible from within the class, and it has a bunch of public methods. Because the Person class and Company class both share the same package, the Company class can access the Person class as well as all its methods.

To complete the demonstration of the access control modifiers, let’s create a driver class in a new project/MainDriver.java file:

import mypackage.*;

public class MainDriver {

    public static void main(String[] args) {

        Company c = new Company();
        c.addPerson("Nic", "Raboy");
        c.printPeople();

        Person p = new Person();
        p.setFirstname("Maria");
        p.setLastname("Campos");

    }

}

Remember, because the Company class is public, we won’t have issues adding and printing people. However, because the Person class is protected, we’re going to get a compile time error since the MainDriver is not part of the mypackage package.

Now let’s take a look at the available non-access modifiers and some example code on how to use them.

ModifierDescription
staticUsed for creating class methods and variables
finalUsed for finalizing implementations of classes, variables, and methods
abstractUsed for creating abstract methods and classes
synchronizedUsed in threads and locks the method or variable so it can only be used by one thread at a time
volatileUsed in threads and keeps the variable in main memory rather than caching it locally in each thread

So how do you use these five non-access modifiers?

A good example of the static modifier is the following in Java:

int max = Integer.MAX_VALUE
int numeric = Integer.parseInt("1234");

Notice in the above example we make use of variables and methods in the Integer class without first instantiating it. This is because those particular methods and variables are static.

The abstract modifier is a little different. You can create a class with methods, but they are essentially nothing more than definitions. You cannot add logic to them. For example:

abstract class Shape {

    abstract int getArea(int width, int height);

}

Then inside a child class you would add code similar to this:

class Rectangle extends Shape {

    int getArea(int width, int height) {
        return width * height;
    }

}

This brings us to the synchronized and volatile modifiers.

Let’s take a look at a threading example where we try to access the same method from two different threads:

import java.lang.*;

public class ThreadExample {

    public static void main(String[] args) {

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                print("THREAD 1");
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                print("THREAD 2");
            }
        });

        thread1.start();
        thread2.start();

    }

    public static void print(String s) {
        for(int i = 0; i < 5; i++) {
            System.out.println(s + ": " + i);
        }
    }

}

Running the above code will result in output that is printed in a random order. It could be sequential, or not, it depends on the CPU. However, if we make use of the synchronized modifier, the first thread must complete before the second one can start printing. The print(String s) method will now look like this:

public static synchronized void print(String s) {
    for(int i = 0; i < 5; i++) {
        System.out.println(s + ": " + i);
    }
}

Next let’s take a look at an example using the volatile modifier:

import java.lang.*;

public class ThreadExample {

    public static volatile boolean isActive;

    public static void main(String[] args) {

        isActive = true;

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                while(true) {
                    if(isActive) {
                        System.out.println("THREAD 1");
                        isActive = false;
                    }
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                while(true) {
                    if(!isActive) {
                        System.out.println("THREAD 2");
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {

                        }
                        isActive = true;
                    }
                }
            }
        });

        thread1.start();
        thread2.start();

    }

}

Running the above code will print the thread number and alternate between them because our volatile variable is a status flag. This is because the flag is stored in main memory. If we remove the volatile keyword, the thread will only alternate one time because only a local reference is used and the two threads are essentially hidden from each other.

Conclusion

Java modifiers can be a bit tricky to understand and it is actually common for programmers to be unfamiliar with a lot of them. This is a great interview question to test your book knowledge too. If I’ve missed any or you think my explanations could be better, definitely share in the comments section.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.