DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 3: Understanding Janus
  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • How to Introduce a New API Quickly Using Micronaut
  • Introducing Graph Concepts in Java With Eclipse JNoSQL

Trending

  • How to Build Real-Time BI Systems: Architecture, Code, and Best Practices
  • Data Lake vs. Warehouse vs. Lakehouse vs. Mart: Choosing the Right Architecture for Your Business
  • AI-Driven Root Cause Analysis in SRE: Enhancing Incident Resolution
  • Cloud Security and Privacy: Best Practices to Mitigate the Risks
  1. DZone
  2. Coding
  3. Java
  4. All About Java Modifier Keywords

All About Java Modifier Keywords

By 
Nic Raboy user avatar
Nic Raboy
·
May. 15, 15 · Interview
Likes (0)
Comment
Save
Tweet
Share
12.8K Views

Join the DZone community and get the full member experience.

Join For Free

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.


 

Java (programming language)

Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 3: Understanding Janus
  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • How to Introduce a New API Quickly Using Micronaut
  • Introducing Graph Concepts in Java With Eclipse JNoSQL

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!