Java • Functions and Program Structure

Access Modifiers — Explain access modifiers (public, private, protected, package-private) (conceptual)

Control who can see and use each part of your Java code with four levels of visibility.

Java programming emblem with a coffee cup, code braces, and terminal
Inside this lesson 10 sections 5 questions 6 figures

SECTION 1

Historical Context & Motivation

In the early days of programming, all variables and functions in a program could be seen and changed by any other part of the code. This might sound convenient, but it led to disastrous bugs—imagine a teammate accidentally overwriting your carefully calculated score variable from a completely unrelated section of the game. As programs grew from a few hundred lines to tens of thousands, developers realized they needed a way to hide internal details and only expose what was truly necessary.

The concept of encapsulation—bundling data with the methods that operate on it and restricting outside access—became one of the pillars of object-oriented programming (OOP). Java, released in 1995 by Sun Microsystems, baked this idea directly into the language through access modifiers—keywords that tell the compiler exactly who is allowed to use a class, method, or variable.

1967 • Simula Introduces OOP

The Simula language introduced the concepts of classes and objects, planting the seed for data hiding and encapsulation in programming.

1972 • Smalltalk Refines Encapsulation

Smalltalk treated everything as an object and enforced strict message-passing, popularizing the idea that internal state should be protected from outside interference.

1983 • C++ Adds Access Keywords

Bjarne Stroustrup added public, private, and protected keywords to C++, giving programmers explicit control over visibility.

1995 • Java Launches with Four Levels

Java shipped with four distinct access levels—public, protected, package-private (default), and private—establishing the system still used today.

The central question access modifiers answer is deceptively simple: "Which parts of my code should other classes be allowed to touch?" Getting this right is the foundation of writing clean, maintainable Java programs.

SECTION 2

Core Principles & Definitions

An access modifier is a keyword you place before a class, method, or variable declaration to control its visibility—that is, which other classes and packages can see and use it. Java provides four levels of access, ranging from the most open to the most restrictive.

1

public

Visible to every class everywhere. Use it for APIs and methods that other programmers need to call.
2

protected

Visible within the same package and also to subclasses in other packages. Useful for inheritance hierarchies.
3

package-private (default)

Visible only within the same package. Applied when you write no keyword at all. Good for helper classes.
4

private

Visible only within the same class. The most restrictive level. Ideal for internal data and helper methods.
✦

KEY TAKEAWAY

Think of access modifiers like the security settings on your phone. Public is your public social media profile—anyone can see it. Protected is like a group chat with family—only relatives (subclasses) and close friends (same package) have access. Package-private is a school group chat—only classmates in your specific class period can read it. Private is your personal journal—only you can read it.

SECTION 3

Visual Explanation

The diagram below shows the four access levels as concentric circles. The innermost circle represents the most restrictive level (private), and each outer ring adds more visibility. Notice how each level includes all the access of the levels inside it.

public — Everywhereprotected — Package + Subclassespackage-private — Same PackageprivateSame Class OnlyMyClassOther class,same packageHelperSubclass inanother packageChildUnrelated class,different packageOtherEach ring includes all access of the rings inside it.
The concentric rings show how each access level expands visibility. Private (innermost) restricts to the class itself. Package-private adds same-package classes. Protected adds subclasses in other packages. Public opens access to all.

In the diagram, MyClass sits at the center and can access everything marked private, package-private, protected, or public within itself. A Helper class in the same package can see everything except private members. A Child subclass from another package can also reach protected members through inheritance. Finally, an unrelated class (Other) in a different package can only see public members.

SECTION 4

How Access Modifiers Work in Practice

When you compile a Java program, the compiler checks every reference to a class, method, or field. If the access modifier does not permit the reference, you get a compile-time error—the program will not even run. This is different from a runtime error; Java catches access violations before your code ever executes.

Syntax Patterns

Each modifier is placed immediately before the data type in a declaration. For the default level (package-private), you simply leave the keyword out entirely.

ModifierSyntax ExampleEffect
publicpublic int score;Any class in any package can read or modify score.
protectedprotected void heal() { }Accessible within the same package and by subclasses elsewhere.
(none — default)int health;Only classes in the same package can see health.
privateprivate String password;Only the class itself can read or change password.

Java access modifier syntax and effects

The Package System

A package is Java's way of organizing related classes into folders. A package declaration at the top of a file (for example, package com.school.game;) tells the compiler which group this class belongs to. Two classes share a package only if their package statements are identical. Both package-private and protected rely on packages for their rules, so understanding packages is essential before choosing the right modifier.

⚠

Common Mistake

Many beginners assume that "no modifier" means "public." It actually means package-private—a deliberate restriction, not an oversight. Always be intentional about which modifier you use.

SECTION 5

Detailed Breakdown — Who Can Access What?

The table below is the single most important reference for access modifiers. It answers one question from four perspectives: given a member declared with a specific modifier, can it be accessed from (1) the same class, (2) another class in the same package, (3) a subclass in a different package, or (4) an unrelated class in a different package?

ModifierSame ClassSame PackageSubclass (other pkg)Any Class (other pkg)
public✅ Yes✅ Yes✅ Yes✅ Yes
protected✅ Yes✅ Yes✅ Yes❌ No
package-private (default)✅ Yes✅ Yes❌ No❌ No
private✅ Yes❌ No❌ No❌ No

Complete access matrix for Java's four access levels

Access Modifier Flowchart — Can ClassB Access a Member of ClassA?Is the member public?YES✅ ACCESS GRANTEDNOSame package as ClassA?YESIs it private?YES❌ ACCESS DENIEDNO✅ ACCESS GRANTEDNOIs ClassB a subclass?Is it protected?YES + protected✅ ACCESS GRANTEDNO❌ DENIED
This flowchart walks through the decision process the Java compiler uses to determine whether one class can access a member of another class. Follow the arrows from top to bottom.

Study the flowchart above to internalize the logic. When you are writing code and choosing a modifier, mentally walk through these questions. The general rule of thumb is to start with private and only widen access when you have a clear reason.

SECTION 6

Worked Example — Designing a Student Class

Imagine you are building a school management system. You need a Student class that stores a name, GPA, and student ID. Let's walk through choosing the right access modifier for each member.

Choosing Access Modifiers for a Student Class

  1. 1

    Step 1 — Identify the Fields

    Our Student class has three fields: name (String), gpa (double), and studentId (String). We also need a method calculateHonorRoll() and a helper method validateGPA().
    Five members to assign modifiers to.
  2. 2

    Step 2 — Apply the Principle of Least Privilege

    Start by making everything private. This is the safest default. All three fields (name, gpa, studentId) should be private because outside code should never directly change a student's GPA or ID without going through validation.
    private String name; private double gpa; private String studentId;
  3. 3

    Step 3 — Widen Access for Public Methods

    Other parts of the system (like a report card generator) need to call calculateHonorRoll(). Since it could be called from any package, we mark it public. We also add public getter methods (getName(), getGPA()) so outside code can read, but not directly change, the data.
    public boolean calculateHonorRoll() { return gpa >= 3.5; }
  4. 4

    Step 4 — Keep Helpers Private

    The method validateGPA() checks that a GPA is between 0.0 and 4.0. No outside class ever needs to call this directly—it's an internal detail. So it stays private.
    private boolean validateGPA(double g) { return g >= 0.0 && g <= 4.0; }
  5. 5

    Step 5 — Consider Protected for Inheritance

    If we plan to create a GraduateStudent subclass that overrides honor roll rules, we might change calculateHonorRoll() to protected so subclasses in other packages can override it, while keeping it hidden from unrelated classes.
    protected boolean calculateHonorRoll() { return gpa >= 3.5; }

SECTION 7

Strengths, Limitations & Comparisons

Each access modifier has situations where it shines and situations where choosing it would be a mistake. Understanding these trade-offs helps you write code that is both flexible and secure.

ModifierWhen to UseWhen to Avoid
publicMain methods, class constructors used by other packages, library APIs that external code must call.Fields (instance variables). Making fields public breaks encapsulation and lets any class change your data.
protectedMethods or fields that subclasses in other packages need to inherit or override.When you don't intend for the class to be extended. Overusing protected can leak internal details.
package-privateUtility classes, helper methods shared only within a single package.When you need cross-package access or when the absence of a keyword might confuse readers.
privateAll fields by default, internal helper methods, anything that is an implementation detail.Methods that the rest of the program genuinely needs to call. Over-restricting causes frustration.

When to use and avoid each access level

🔒

THE GOLDEN RULE

Follow the Principle of Least Privilege: give each member the narrowest access that still lets the program work. It is like locking all the doors in a building and then only handing out keys to the people who truly need them. This limits the damage any single mistake can cause.

SECTION 8

Connection to Advanced Topics

Access modifiers are not just a beginner concept—they are the foundation for many advanced programming patterns. As you continue learning Java, you will encounter more sophisticated uses of visibility control.

What You Learn NowWhere It Leads
private fields with public getters/settersEncapsulation — core OOP principle, enforced in frameworks like JavaBeans and Spring.
protected methods for subclass overridingPolymorphism and Inheritance — advanced OOP that enables flexible, reusable designs.
Package-private helper classesModular design — Java 9 introduced the Module System (Jigsaw) for even stronger encapsulation boundaries.
Choosing the right modifierAPI design — professional libraries carefully choose which methods to expose, as changing a public method later can break thousands of other programs.

How access modifiers connect to advanced Java concepts

When you eventually study design patterns like Singleton or Factory, you will see that access modifiers are the key mechanism that makes them work. A Singleton class, for example, hides its constructor with private and provides a single public method to retrieve the one instance. Understanding access modifiers now gives you the vocabulary for these powerful techniques later.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

A student writes a class and declares a field as int count; without any keyword before the type. What access level does this field have, and from which locations can it be accessed?
Show answer
When no access modifier keyword is specified, Java assigns the package-private (default) access level. This means count can be accessed by any class within the same package, but it cannot be accessed by classes in a different package—even subclasses. Many beginners mistakenly believe no keyword means public, but it is actually more restrictive. The field is accessible from the same class and from other classes that share an identical package declaration.

Question 2: BASIC CALCULATION

Consider the following class in package com.school: public class Dog { private String name; public int age; protected void bark() {} } A class Kennel is in the same package (com.school) but is NOT a subclass of Dog. Which members of Dog can Kennel access?
Show answer
Kennel can access age (public — accessible everywhere) and bark() (protected — accessible within the same package). It cannot access name because it is private, meaning only the Dog class itself can see it. Remember that protected grants same-package access as well as subclass access, so even though Kennel is not a subclass, it still gets access because it is in the same package.

Question 3: INTERMEDIATE

Class Vehicle is in package com.transport and has a protected int speed; field. Class Car extends Vehicle but lives in package com.cars. Can a method inside Car read speed? Now suppose class Garage is also in com.cars but does NOT extend Vehicle. Can Garage read speed from a Car object?
Show answer
Yes, Car can read speed because protected allows subclasses in other packages to access the member through inheritance. However, Garage cannot directly access speed on a Car object. Even though Garage is in the same package as Car, the protected field speed was declared in Vehicle (a different package). Protected access from outside the declaring package is only available through inheritance, not through other classes in the subclass's package. This is a subtle but important distinction.

Question 4: APPLIED

You are designing a BankAccount class. It has a balance field, a deposit() method, a withdraw() method, and an internal logTransaction() helper method. Choose the best access modifier for each and justify your choices.
Show answer
The balance field should be private because you never want external code to directly set a balance to an arbitrary value—all changes should go through deposit() or withdraw(), which can validate the amount. Both deposit() and withdraw() should be public because these are the main operations other parts of the program (like an ATM class) need to call. The logTransaction() method should be private because it is an internal implementation detail that outside code should never invoke directly. This design follows the Principle of Least Privilege.

Question 5: CRITICAL THINKING

A classmate argues: "I just make everything public because it's simpler and I never get compiler errors about access." Write a paragraph explaining at least two specific problems this approach could cause in a large team project, and suggest a better strategy.
Show answer
Making everything public creates two major problems. First, it destroys encapsulation: if a field like balance is public, any teammate can write account.balance = -5000; and put the object into an invalid state, causing bugs that are extremely hard to trace. Second, it creates tight coupling: if every internal method is public, other classes will start depending on those methods. When you later refactor or rename an internal method, you break every class that used it. A better strategy is to start with everything private, then promote only the members that genuinely need wider access. Public fields should almost always be replaced with private fields plus public getter and setter methods that include validation logic.

SUMMARY

Summary

Summary

Java provides four access modifiers that control the visibility of classes, methods, and fields. public makes a member accessible from any class anywhere. protected allows access within the same package and from subclasses in other packages. Package-private (the default, with no keyword) restricts access to classes in the same package. private is the most restrictive, allowing access only within the declaring class itself.

The guiding principle is least privilege: start with private and widen access only when necessary. Fields should almost always be private with public getter and setter methods to preserve encapsulation. Mastering access modifiers is essential for writing clean, maintainable, and secure Java programs.

Varsity Tutors • Java • Access Modifiers — Explain access modifiers (public, private, protected, package-private) (conceptual)