All About Java Modifier Keywords
Join the DZone community and get the full member experience.
Join For FreeI’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:
- Access control modifiers
- Non-access modifiers
Let’s first take a look at the access control modifiers and see some code examples on how to use them.
Modifier | Description |
---|---|
public | Visible to the world |
private | Visible to the class |
protected | Visible 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.
Modifier | Description |
---|---|
static | Used for creating class methods and variables |
final | Used for finalizing implementations of classes, variables, and methods |
abstract | Used for creating abstract methods and classes |
synchronized | Used in threads and locks the method or variable so it can only be used by one thread at a time |
volatile | Used 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.
Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments