The Java Tutorial: Access Modifiers

Access modifiers control how classes can access the properties and methods of other classes. Access modifiers are important because they make your code more maintainable and provide encapsulation.

Using access modifiers, you can make fields read-only/write-only and have complete control over what other classes can and can't access. This makes code both more readable and less error prone.

Access levels in Java

Following is an explanation of each access modifier in Java including basic examples and best use cases:

public

The public access modifier indicates a certain class, property, or method is 'publicly' available to other classes:

//ClassA.java
package myPackage;

public class ClassA {
    int myAge = 43;
}
//MainClass.java
package otherPackage;
import myPackage.*;

public class MainClass {
    public static void main(String[] args){
        ClassA myClass = new ClassA();
        System.out.println(myClass.myAge); //prints 43
    }
}

Notice the use of the public keyword when defining a new class. This makes the class 'publicly' available to other classes outside this package myPackage. Without specifying public in our ClassA definition, we wouldn't be able to create our myClass instance of ClassA.

The Default Access Modifier

The default modifier is 'package-private', meaning accessible within it's own package. When an access level is not specified, 'package-private' is the assumed access level.

When should I use public?

Use public when you want everyone to have access. This generally applies to any class you want to instantiate from any other class.

Be careful not to overuse public as it limit's code flexibility. Outside reference to a class's public properties generates unwanted dependencies. Any change to a publicly accessible variable x requires an update for everything that references x.

private

The private access modifier indicates a certain property or method is only accessible to the class it's defined in:

//ClassA.java
package myPackage;

public class ClassA {
    private int myAge = 43;
}
//MainClass.java
package myPackage;

public class MainClass {
    public static void main(String[] args){
        ClassA myClass = new ClassA();
        System.out.println(myClass.myAge); //compile time error
    }
}

Notice how we define a single property myAge inside ClassA. By using the private modifier, we are saying that myAge is only accessible within ClassA itself. This means other classes can't have direct access to myAge.

Since the separate MainClass is trying to access myClass.myAge, we get a compile-time error.

More on private...

The private access modifier is only available at the member level. This means outer classes can't be declared private.

When should I use private?

Use private when you want a property or method to only be accessible by the class it's declared in. Considering OOP principles and encapsulation, declaring class members as private is usually a safe bet.

protected

The protected access modifier provides the default 'package-private' access level with additional access for subclasses:

//ClassA.java
package myPackage;

public class ClassA {
    protected int myAge = 43;
}
//MainClass.java
package otherPackage;
import myPackage.*;

public class MainClass extends ClassA {
    public MainClass(){
        System.out.println(this.myAge);
    }
}

In this example, we are still able to access myAge from within MainClass because it's a subclass of ClassA. While 'package-private' access would normally prevent us from accessing myAge from a different package, the protected access modifier allows us to access the variable from any subclass of ClassA

When should I use protected?

Use protected when you want a subclass to have access outside of the default 'package-private'.

Conclusion

Access modifiers are fundamental to encapsulation and OOP in Java. Using access modifiers, you can control what classes have access to what properties/methods. While the default 'package-private' restricts access at the package level, using private provides further restrictions by only allowing internal access to properties/methods. While public is commonly used to give other packages access to a given class, it should be generally avoided because of the dependencies it generates. Using protected plays well with extensibility as subclasses from foreign packages can still access otherwise restricted properties.

Your thoughts?