Access Modifiers in JAVA

This post describes the importance of access modifiers in JAVA

10/10/20234 min read

Java offers a powerful feature known as access modifiers. Access modifiers play a pivotal role in defining the visibility and accessibility of classes, fields, methods, and other members within a Java program. These modifiers are crucial for encapsulation, information hiding, and ensuring the security and integrity of Java code.

Java provides four primary access modifiers:

1. `public`: The most permissive access modifier, `public` members are accessible from anywhere, both within the same package and from other packages. Public members have the widest scope and visibility.

2. `private`: The most restrictive access modifier, `private` members are accessible only within the same class. They are hidden from other classes and cannot be accessed directly.

3. `protected`: `protected` members are accessible within the same class, the same package, and subclasses (even if they are in different packages). This modifier promotes a level of encapsulation while allowing inheritance.

4. `default` (package-private): When no access modifier is specified, the default access modifier is applied. `default` members are accessible within the same package but not from outside. They offer a balance between encapsulation and visibility within a package.

Visibility Control with `public` Access Modifier

The `public` access modifier grants the highest level of visibility, allowing classes, fields, methods, and other members to be accessed from any part of the Java program. Here's a closer look at how it works:

1. Public Classes

A class marked as `public` can be accessed from anywhere. This means that other classes in the same package or in different packages can create instances of the `public` class and call its methods.

public class MyTemp {

public int age;

}

// Accessing a public class from another package

import com.example.MyClass;

public class SeparateClass {

public static void main(String[] args) {

MyTemp temp = new MyTemp(); // Creating an instance of the public class

temp.age=40;

}

}

2. Public Methods

Public methods can be called from anywhere, making them suitable for defining the entry points of your classes or libraries. They are commonly used for exposing functionality to other parts of the program.

public class Calculator {

// Public method for multiplication

public int multiply(int a, int b) {

return a + b;

}

}

public class Main {

public static void main(String[] args) {

Calculator calculator = new Calculator();

int result = calculator.multiply(9, 3); // Calling a public method

}

}

3. Public Fields

Public fields are directly accessible and can be modified from any part of the program. However, it's generally considered a good practice to encapsulate fields using getter and setter methods for better control.

public class Square {

public double side; // Public field

public double calculateArea() {

return side*side;

}

}

}

Hiding Implementation Details with `private` Access Modifier

In contrast to the `public` modifier, the `private` access modifier enforces strict encapsulation by hiding class members from external access. Members marked as `private` can only be accessed within the same class. This is essential for information hiding and maintaining the integrity of an object's internal state.

1. Private Fields

Private fields are used to encapsulate the state of a class, preventing direct access and modification from external code. To access or modify private fields, you typically use getter and setter methods.

public class Person {

private String name;

public String getName() {

return name;

}

public void setName(String newName) {

name = newName; // Setter method to modify the private field

}

}

2. Private Methods

Private methods are often used for implementing internal logic within a class. They cannot be called from outside the class, making them hidden implementation details.

public class Employee {

private void calculateAge() {

// Private method for calculating salary

}

public void printAge() {

calculateAge(); // Calling a private method from within the same class

}

}

3. Private Constructors

Private constructors are a special case. When a class has a private constructor, it cannot be directly instantiated from outside the class. This pattern is often used for implementing Singleton classes or classes with static utility methods.

public class Singleton {

private static Singleton instance; // Private field

private Singleton() {

// Private constructor to prevent external instantiation

}

public static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

Balanced Accessibility with `protected` Access Modifier

The `protected` access modifier is more flexible than private access modifier but less flexible than public access modifier, it strikes a balance between visibility and encapsulation. It allows class members to be accessed within the same class, the same package, and the subclasses can be in the same or different packages.

1. Protected Fields

Protected fields are accessible within the same class, the same package, and by subclasses. This makes them suitable for situations where you want to provide controlled access to certain fields.

package com.example;

public class Vehicle {

protected String color; // Protected field

public Vehicle(String color) {

this.color = color;

}

}

package com.example;

public class Car extends Vehicle {

public Car(String color) {

super(color);

}

public void displayMake() {

System.out.println("color: " + color); // Accessing a protected

field from a subclass

}

}

2. Protected Methods

Protected methods can be called within the same class, the same package, and by subclasses. This facilitates code reuse and extensibility while maintaining a level of control over method access.

package com.example;

public class Animal {

protected void eat() {

// Protected method for making a sound

}

}

package com.example;

public class Dog extends Animal {

public void eatPetFood() {

eat(); // Accessing a protected method from a subclass

}

}

Package-Private (`default`) Access Modifier

When no access modifier is specified (often referred to as the "default" modifier), the class member is accessible only within the same package. This level of visibility is often used to restrict access to certain elements while still allowing interaction within a package.

Package-Private Fields

Package-private fields are accessible within the same class and any other class within the same package. They are hidden from classes in different packages.

package com.example;

public class Circle {

double radius;

double calculateArea() {

return Math.PI radius radius;

}

}

Package-Private Classes

They are also known as Default access modifer. They are not explicitly marked with an access modifier (i.e., they have default visibility). They are accessible only within the same package and cannot be accessed from outside.

package com.example;

class Helper {

// Package-private class

void doSomething() {

// Logic here

}

}

Choosing the Right Access Modifier

Choosing the appropriate access modifier is a crucial decision in Java programming, as it directly impacts the design, encapsulation, and maintainability of your code. Here are some guidelines to help you make the right choice:

1. Use `private`: Mark fields as `private` to encapsulate the internal state of a class. Expose controlled access to these fields through getter and setter methods.

2. Use `protected`: Use `protected` when you want to allow access to certain members within the same package and by subclasses. This is particularly useful for implementing class hierarchies and frameworks.

3. Use `default` (package-private): Consider using the default access modifier when you want to restrict access to elements within the same package. This is used for encapsulation and information hiding within a package.

4. Use `public`: Use `public` for elements that need to be accessed from anywhere in your program. This is often used for utility classes, constants, and entry points.

Summary

Access modifiers in Java are responsible for controlling the visibility and accessibility of class members. By choosing the right access modifier for each member, you can achieve a balance between encapsulation and interaction within your code.

Streams in JAVA 8