Java Access Modifiers
Access modifiers are Java keywords that decide where a class, field, method, or constructor can be accessed in a program. Java provides public, protected, and private keywords. If we do not write an access modifier for a field or method in a class, Java gives it package-private access. Only classes in the same package can use it. A package is a group of related Java classes. The same rule applies to constructors and classes written outside other classes.
Simple Example of Package-Private Access
class Person {
void showName() { // No access modifier: package-private
System.out.println("Name: Mira");
}
}
public class HelloWorld {
public static void main(String[] args) {
Person person = new Person();
person.showName();
}
}Output:
Name: MiraWe did not write public, protected, or private before showName(). The method therefore has package-private access. Person and HelloWorld have no package statement, so both belong to the same unnamed package. HelloWorld can call showName() because it is in that package. A class in another package cannot call this method directly.
A class may have some data that other classes can use and some data that it should keep private. Access modifiers control this access. We can use them with classes, fields, methods, and constructors. We can also use them with classes declared inside another class.
Java has four access levels: private, package-private, protected, and public. These levels decide where a class or its members can be used. For example, some members are available only inside their class, while others are available to classes in the same package. For package-private access, we do not write an access keyword. A package is a group of related Java classes.
Why Do We Need Access Modifiers?
Suppose a class stores a person's age. We do not want another class to assign a negative age. We can make age private. We then provide a public method that checks the value before storing it.
class Person {
private int age;
public void setAge(int newAge) {
if (newAge >= 0) {
age = newAge;
}
}
public int getAge() {
return age;
}
}
public class HelloWorld {
public static void main(String[] args) {
Person person = new Person();
person.setAge(20);
System.out.println(person.getAge());
// person.age = -4; // Does not compile: age is private.
}
}Output:
20The age field starts at 0. Calling setAge(20) stores 20 because it is not negative. Calling getAge() returns that value. HelloWorld cannot change age directly because the field is private.
Access Levels at a Glance
The table below shows where fields and methods of a class can be used. Before using a member, the calling code must also be able to access the class that contains it.
| Access level | Declaring class | Unrelated class in same package | Subclass in another package | Unrelated class in another package |
|---|---|---|---|---|
| private | Yes | No | No | No |
| Package-private | Yes | Yes | No | No |
| protected | Yes | Yes | Yes, with restrictions | No |
| public | Yes | Yes | Yes | Yes |
There is one detail about private access to remember. A class declared inside another class is called a nested class. Nested classes inside the same outermost class can access private members of that class and of each other. The table shows the rule for separate classes that do not share this outermost class.
Save each single-file example separately as HelloWorld.java. Package examples below show their own file paths.
1. public Access Modifier
public allows code in the same package or another package to use a class or member. For a member, Java also checks whether the type used to access it is available to the calling code. If the program uses modules, their access rules must also allow it.
Use public when other classes need to call a method or use a field. The calling code must still be able to access the class containing that member. Making a method public does not automatically make its class public.
class Person {
public String name = "Mira";
public void showName() {
System.out.println("Name: " + name);
}
}
public class HelloWorld {
public static void main(String[] args) {
Person person = new Person();
person.showName();
}
}Output:
Name: MiraHelloWorld creates a Person object and calls showName(). Both classes are in the same package, so HelloWorld can access Person. If a class in another package needs to use Person, declare it public too. Save that public class in a separate file named Person.java.
Java applications can also be divided into modules. In that case, the calling module must be allowed to use the other module, and the needed package must be exported. A public declaration must still follow these module rules. You do not need modules to run the examples on this page.
2. private Access Modifier
private keeps a member hidden from other separate classes. Code inside its class can use it. Nested classes inside the same outermost class can also access it. The examples below use separate classes, so HelloWorld must call a public method instead of reading the private field directly.
Use private for data or methods that other separate classes should not access directly. Methods inside the same class can still use a private field. In this example, showName() reads the private name field.
class Person {
private String name = "Mira";
public void showName() {
System.out.println(name);
}
}
public class HelloWorld {
public static void main(String[] args) {
Person person = new Person();
person.showName();
// System.out.println(person.name); // Does not compile: name is private.
}
}Output:
MiraHelloWorld calls showName(), and that method prints name. HelloWorld cannot read person.name directly. Remove the comment marks from that line to see the compiler error. private controls access in Java code; it does not encrypt the stored name.
3. Package-Private Access
Package-private access lets classes in the same package use a class or member. Classes in other packages cannot use it directly. For a top-level class or an ordinary class member, we get this access by not writing an access keyword.
If we do not write public, protected, or private on an ordinary class member, it has package-private access. Other classes in the same package can use it. Classes in another package cannot. For example, people and people.tools are different packages, even though their names start the same way.
class Person {
int age = 20;
void showAge() {
System.out.println("Age: " + age);
}
}
public class HelloWorld {
public static void main(String[] args) {
Person person = new Person();
person.showAge();
}
}Output:
Age: 20The example has no package statement, so both classes belong to the unnamed package. They can use each other's package-private members. The next example uses a package named people. Save each file in the folder shown above its code.
File: people/Person.java
package people;
public class Person {
void showAge() {
System.out.println("Age: 20");
}
}File: people/HelloWorld.java
package people;
public class HelloWorld {
public static void main(String[] args) {
Person person = new Person();
person.showAge();
}
}Compile and run from the folder containing people:
mkdir out
javac -d out people/Person.java people/HelloWorld.java
java -cp out people.HelloWorldOutput:
Age: 20Person is public, but showAge() has no access keyword. HelloWorld can call it because both files say package people. A class in another package cannot call it. Adding an import statement does not remove this restriction.
4. protected Access Modifier
protected lets classes in the same package use a member. A child class in another package can also use an inherited protected member. For an instance field or method used through a variable in that child class, the variable must have the child type or a type that extends it. A variable with only the parent type does not give this access. Protected constructors follow some extra rules.
protected gives access to classes in the same package. It also allows a child class in another package to use an inherited member, with some restrictions. In the examples below, Student is a child of Person. The child uses the name field defined in the parent.
Same-Package Example
class Person {
protected String name = "Mira";
}
class Student extends Person {
public void showName() {
System.out.println("Name: " + name);
}
}
public class HelloWorld {
public static void main(String[] args) {
Student person = new Student();
person.showName();
}
}Output:
Name: MiraDifferent-Package Example
Save these two files separately. The parent class is public so the child can extend it from another package. The extends keyword creates the parent-child relationship. The import statement lets us use the parent class name without writing its full package name each time.
File: people/Person.java
package people;
public class Person {
protected String name = "Mira";
}File: students/HelloWorld.java
package students;
import people.Person;
public class HelloWorld extends Person {
public static void main(String[] args) {
HelloWorld child = new HelloWorld();
System.out.println(child.name);
Person person = child;
// System.out.println(person.name); // Does not compile here.
}
}Use a fresh output folder. Compile and run from the folder containing people and students:
mkdir out
javac -d out people/Person.java students/HelloWorld.java
java -cp out students.HelloWorldOutput:
MiraHelloWorld is a child of Person, but the two classes are in different packages. The variable child has type HelloWorld, so child.name is allowed inside this child class. The variable person has the parent type Person, so person.name is not allowed here. Both variables refer to the same object, but their declared types are different.
For a protected instance member in another package, check the type of the variable before the dot. Inside the child class, that variable must have the child type or a type that extends the child. A variable with only the parent type does not meet this rule. This is why extending a class does not allow access through every parent reference.
Access Modifiers with Classes and Constructors
A top-level class is a class written outside every other class. A member class is written inside another class, but outside its methods. A local class is written inside a method or another block. These locations affect which access modifiers are allowed.
- A top-level class can be public or package-private. It cannot be private or protected.
- A member class can use any of the four access levels. Local classes do not accept access modifiers.
- Class constructors can use public, protected, package-private, or private access. Enum constructors have special restrictions.
- Local variables do not accept public, protected, or private.
Example: A Private Constructor
The next class has a private constructor. HelloWorld cannot call that constructor directly. Instead, it calls the public create() method. That method is inside Person, so it can call the private constructor and return a new object.
class Person {
private Person() {
}
public static Person create() {
return new Person();
}
public void show() {
System.out.println("Person created");
}
}
public class HelloWorld {
public static void main(String[] args) {
Person person = Person.create();
person.show();
// new Person(); // Does not compile: the constructor is private.
}
}Output:
Person createdAccess Modifiers and Overriding
Suppose a parent class has a public showName() method. If a child overrides this method, its version must also be public. The child cannot make the method harder to access. A private method is different because the child does not inherit it. If the child declares a method with the same name and parameters, that method is a separate method, not an override.
Common Mistakes
- Do not write default before a field or ordinary class method to request package access. Omit the access keyword instead. The default keyword has a separate use for interface methods.
- Do not combine public and private on one declaration. Choose one access level.
- Do not assume protected means subclasses only. Unrelated classes in the same package also have access.
- A public method in an inaccessible class does not automatically make that class available to other packages.
Easy way to remember
- Keep fields private when other classes should not change them directly. Provide methods for the changes you want to allow.
- Use package-private access when a helper class or method is needed only in the same package.
- When using protected across packages, check both the child class and the type of the variable before the dot.
- Check both the class and the member when deciding whether access is allowed.
Continue with Java Non-Access Modifiers to learn how modifiers change behavior.
See you in next page....🙂