Access control & packages
public/protected/private/package access, the package/import library unit, and the silent default.
The library unit: a package
A package is Java's unit of reuse and namespacing. The package statement is the *first* non-comment line of a source file and maps directly to a directory path: a class declared package com.greenhouse.events; must live in com/greenhouse/events/. Other code pulls it in with import com.greenhouse.events.Event; (one type) or import com.greenhouse.events.*; (all public types of that package, not sub-packages). Without an import you must use the fully-qualified name com.greenhouse.events.Event.
The four access levels
Java has four access levels for members (fields, methods, constructors), ordered most-open to most-closed:
- public — any code anywhere can access it. It is the deliberate, published interface of your class.
- protected — the same package *and* subclasses (even in other packages). It says "this is for people extending me."
- package-private (the *default* — no keyword) — only code in the same package. This is the level you get when you forget to write a modifier.
- private — only the *enclosing class* itself. The implementation detail nobody outside touches.
A top-level class itself may be only public or package-private (default). There is no private or protected top-level class.
Worked example: a two-class package with mixed access
package bank;
public class Account {
private double balance; // hidden from everyone
protected String owner; // visible to subclasses + package
double feeRate = 0.01; // package-private (default)
public void deposit(double amt) { balance += amt; }
public double getBalance() { return balance; }
}
package bank; // SAME package as Account
class Auditor {
void check(Account a) {
System.out.println(a.getBalance()); // OK: public
System.out.println(a.feeRate); // OK: same package sees default
// System.out.println(a.balance); // COMPILE ERROR: private
}
}
Auditor reaches feeRate only because it shares the bank package. Move Auditor to another package and that line stops compiling — but getBalance() keeps working because it is public. The rule of thumb: expose as little as possible. Make fields private and reach them through methods so you can change the internals later without breaking callers.