Skip to main content

Packages and Access Modifiers

Easy

Interview Question: "What exactly is a package in Java? More specifically, how does the concept of a package dictate how the 'default' and 'protected' access modifiers actually behave?"

The filing cabinet analogy​

Imagine organizing a huge filing cabinet for a growing company. Throw 1,000 loose papers into one drawer, and it's chaos — worse, if you have an Invoice from 2024 and another Invoice from 2025 in the same drawer, nobody knows which is which.

The fix is labeled folders: a Billing folder and an HR folder. Now an Invoice inside Billing (com.app.billing.Invoice) and a totally different Invoice inside HR (com.app.hr.Invoice) can coexist without confusion.

In Java, your .java files are the loose papers, and packages are the folders. A package is just a namespace that maps directly onto a real directory on disk — it groups related classes together and keeps names from colliding across the codebase.

How access modifiers depend on those folders​

ModifierSame ClassSame PackageSubclass (Different Package)World (Different Package)
publicYesYesYesYes
protectedYesYesYes (via inheritance only)No
default (no modifier)YesYesNoNo
privateYesNoNoNo
  • default (package-private): visible only to classes physically sitting in the same folder.
  • protected: visible in the same folder, plus to subclasses anywhere else, but only through inheritance.

Same folder vs. different folder​

  • Same package (neighbors): if User.java and UserValidator.java both declare package com.myapp.users;, they sit in the same directory. They can freely use each other's default and protected members without needing public getters/setters.
  • Different package (a different city): if Payment.java lives in com.myapp.billing, it can't touch User.java's default-access fields, even though both are part of the same app.

The protected subtlety across packages​

A subclass in a different package can only reach an inherited protected member through its own instance (or super) — not through some other, unrelated instance of the parent class:

package com.myapp.billing;
import com.myapp.users.User;

public class PremiumUser extends User {
public void inspect() {
// Allowed: accessed via inheritance on 'this'
System.out.println(this.protectedUserId);

// Compilation Error! Cannot access protected member on a foreign parent instance
User foreignUser = new User();
// System.out.println(foreignUser.protectedUserId);
}
}

Package declarations across languages​

// File path must strictly match: src/main/java/com/myproject/models/User.java
package com.myproject.models;

public class User {
private String id;
String packagePrivateNote; // Accessible only to classes in com.myproject.models
protected String role; // Accessible to models package + subclasses everywhere
public String email; // Universally accessible
}

Two things worth knowing​

Why you never import String, Math, or System. Every Java file automatically imports everything public in java.lang — it's as if import java.lang.*; is silently written at the top of every file, per the Java Language Spec.

Package-private as a design tool. It's tempting to make every class public, but a lot of well-structured code deliberately doesn't. In Domain-Driven Design or hexagonal architecture, you might expose a public interface PaymentGateway while keeping its real implementation, class StripePaymentGateway, package-private — visible only inside that package. A public factory builds and hands back the interface type, so nothing outside the package can reach or depend on the concrete class directly.


Say this in the interview​

"A package is a namespace mapped directly onto a folder on disk — it groups related classes and prevents naming collisions. That physical mapping is what drives Java's access rules: default (package-private) access is limited strictly to classes in the same folder, and protected extends that to subclasses in other packages, but only through inheritance — you can't reach a protected member on some unrelated instance of the parent. Beyond access control, package-private visibility is also a design tool: you can expose a public interface while keeping its implementation hidden inside the package, so nothing outside can depend on it directly."