Public vs Private
Protected
Access Modifiers
Programming Concepts
Software Development

What is the difference between public, private, and protected?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

public, private, and protected are access modifiers used to control who can use a class member. They are central to encapsulation because they let you decide which parts of a type are part of its external API and which parts stay internal to the implementation.

public Exposes Members Broadly

A public member is part of the type's visible interface. Other code can call it directly, which makes it appropriate for behavior you intentionally support for consumers.

java
1public class Vehicle {
2    public void start() {
3        System.out.println("Starting");
4    }
5}
6
7public class Main {
8    public static void main(String[] args) {
9        Vehicle vehicle = new Vehicle();
10        vehicle.start();
11    }
12}

The key tradeoff is that public APIs are harder to change later without breaking callers. Make something public only when you want other code to depend on it.

private Hides Implementation Details

private members are accessible only inside the same class. This is the default choice for state or helper methods that should not be touched from the outside.

java
1public class BankAccount {
2    private double balance;
3
4    public void deposit(double amount) {
5        validateAmount(amount);
6        balance += amount;
7    }
8
9    private void validateAmount(double amount) {
10        if (amount <= 0) {
11            throw new IllegalArgumentException("amount must be positive");
12        }
13    }
14}

Here, callers can deposit money, but they cannot bypass the validation logic. That is exactly what good encapsulation is supposed to achieve.

protected Allows Subclass Access

protected sits between public and private. In many object-oriented languages, a protected member is available inside the class and inside derived classes. In Java, it is also visible to classes in the same package.

java
1public class Animal {
2    protected void makeSound() {
3        System.out.println("generic sound");
4    }
5}
6
7public class Dog extends Animal {
8    public void bark() {
9        makeSound();
10    }
11}

This is useful when subclasses legitimately need access to extension points, but the member should not be part of the general public API.

The Meaning Depends on the Language

The general ideas are consistent, but details vary by language:

  • Java protected also includes package-level visibility
  • C# protected is for the type and subclasses, not the whole assembly
  • some languages add more modifiers such as internal, fileprivate, or package-private defaults

So when you read advice about access modifiers, always map it to the actual language semantics you are working with.

How to Choose in Practice

A practical rule is:

  • start with private
  • widen to protected only if subclasses need it
  • widen to public only if outside callers need it

This "most restrictive first" approach keeps your API smaller and your refactoring options wider.

It also makes code easier to reason about. When fewer parts are exposed, fewer parts can be misused or coupled too tightly to current implementation details.

Design Example: Public Method, Private State

Good class design often combines a small public surface with private state and helpers.

java
1public class TemperatureSensor {
2    private double lastReading;
3
4    public void record(double reading) {
5        if (!isValid(reading)) {
6            throw new IllegalArgumentException("invalid reading");
7        }
8        lastReading = reading;
9    }
10
11    public double currentValue() {
12        return lastReading;
13    }
14
15    private boolean isValid(double reading) {
16        return reading > -100 && reading < 200;
17    }
18}

Consumers get a clear public API, while validation details stay hidden and changeable.

Common Pitfalls

  • Making fields public when access should go through validated methods.
  • Using protected too freely and creating fragile inheritance-based coupling.
  • Forgetting that modifier semantics differ between languages.
  • Exposing helpers publicly just to make testing easier instead of testing through behavior.
  • Treating access modifiers as style choices instead of design decisions.

Summary

  • 'public exposes a member to outside callers.'
  • 'private keeps a member inside the class only.'
  • 'protected usually allows access from subclasses, with language-specific details.'
  • Start with the most restrictive modifier and widen only when needed.
  • Good access control improves encapsulation, maintainability, and API stability.

Course illustration
Course illustration

All Rights Reserved.