Ch. 2 Object Oriented Concepts.

2.2 Access Specifiers

Introduction

In Object-Oriented Programming, encapsulation is a core principle that involves bundling the data (fields) and methods that operate on the data into a single unit (the class). A key aspect of encapsulation is controlling how the internal state of an object can be accessed or modified from outside the class. This is where access specifiers (also known as access modifiers) come into play.

Access specifiers in Java determine the visibility of a class, its fields (variables), and its methods. They define the scope from which these members can be accessed. By using them, you can protect your data from unauthorized access or modification, enforce proper usage, and make your code more robust and maintainable.

Java provides four main access specifiers:

  • public
  • protected
  • private
  • default (or package-private)

Explanation

The choice of access specifier dictates who can "see" and "use" a particular member of a class. This mechanism is vital for implementing information hiding, allowing developers to expose only what is necessary and hide the internal implementation details.

2.2.1 public

Introduction

The public access specifier is the least restrictive. When a class, field, or method is declared as public, it is accessible from anywhere in the program.

Explanation

Members declared public have the widest scope. They can be accessed:

  • From any other class in the same package.
  • From classes in different packages.

Typically, public is used for methods that define the public interface of a class—the operations that other parts of the system are intended to use. Fields are rarely made public directly, as this can break encapsulation.

 // In file: MainApp.java

package finance;

 

import bank.BankAccount;

 

public class MainApp {

    public static void main(String[] args) {

        // Create a new BankAccount object

        BankAccount myAccount = new BankAccount("12345", 1000.00);

 

        // Display account info

        myAccount.displayAccountInfo();

 

        // Deposit money

        myAccount.deposit(500.00);

 

        // Check current balance using getter

        System.out.println("Current balance: $" + myAccount.getBalance());

 

        // Direct access to public field (not recommended)

        myAccount.accountNumber = "98765";

        System.out.println("Updated Account Number: " + myAccount.accountNumber);

    }

}

2.2.2 protected

Introduction

The protected access specifier allows members to be accessed:

  • Within the same package.
  • By subclasses (even if they are in different packages).

Explanation

protected is commonly used in inheritance scenarios where subclasses require controlled access to parent class members.

Example

 // File: bank/SavingsAccount.java

package bank;

 

/**

 * Subclass representing a savings account

 */

public class SavingsAccount extends BankAccount {

    // Additional field for interest rate

    private double interestRate;

 

    // Constructor

    public SavingsAccount(String accNum, double initialBalance, double rate) {

        super(accNum, initialBalance); // Call to parent constructor

        this.interestRate = rate;

    }

 

    // Method to apply interest to the balance

    public void applyInterest() {

        double interest = getBalance() * interestRate;

        updateBalance(interest); // Accessing protected method from parent

    }

}

 

2.2.3 private

Introduction

The private access specifier is the most restrictive. Members declared as private:

  • Can only be accessed within the same class.
  • Are not accessible by subclasses or other classes in the same package.

Explanation

private is commonly used for fields to ensure strong encapsulation. Controlled access is provided via getters and setters.

Example

 // File: bank/BankAccount.java

package bank;

 

/**

 * Class representing a basic bank account

 */

public class BankAccount {

    // Private fields (encapsulation)

    private String accountNumber;

    private double balance;

 

    // Constructor to initialize account

    public BankAccount(String accNum, double initialBalance) {

        this.accountNumber = accNum;

        this.balance = initialBalance;

    }

 

    // Public getter for account number

    public String getAccountNumber() {

        return accountNumber;

    }

 

    // Public getter for balance

    public double getBalance() {

        return balance;

    }

 

    // Public method to deposit money

    public void deposit(double amount) {

        if (amount > 0) {

            balance += amount;

            logTransaction("Deposit", amount); // Log the deposit

        } else {

            System.out.println("Deposit amount must be positive.");

        }

    }

 

    // Private method to log transactions

    private void logTransaction(String type, double amount) {

        System.out.println("Transaction: " + type + ", Amount: $" + amount);

    }

}

 

2.2.4 default (package-private)

Introduction

When no access specifier is provided, the member is said to have default (package-private) access.

Explanation

Default members:

  • Can be accessed by any class in the same package.
  • Cannot be accessed from outside the package.

Example

 // File: bank/BankAccount.java

package bank;

 

/**

 * A simple BankAccount class demonstrating default access

 */

public class BankAccount {

    // Fields with default (package-private) access

    String accountNumber; // Accessible within the same package

    double balance;       // Accessible within the same package

 

    /**

     * Internal method to apply some process on the balance

     * Default access (package-private)

     */

    void internalProcess() {

        balance *= 1.01; // Example: Apply 1% increase

    }

}