Java Access Modifiers

In the last lesson you learned about the Java hashCode() method. Now let’s talk about who is even allowed to touch your code. Every field and method has a door, and you decide who walks through it. That door is the access modifier. Let’s learn the four levels Java gives you.

πŸ€” The problem: everything is exposed

A BankAccount with an open balance field is trouble. Any line anywhere can change it directly.

class BankAccount {
int balance; // anyone can touch this
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.balance = -5000; // ❌ a negative balance, no rules checked
System.out.println(account.balance);
}
}

The balance just became negative. No check ran. No rule stopped it.

  • The field was wide open, so any line could set it to anything.
  • The fix is to control the door. Some parts open, some parts locked.
  • Access modifiers say β€œthis part is open” or β€œthis part is private.”

🧩 What access modifiers control

An access modifier is a keyword in front of a class or a member. A member is a field or method inside a class. It decides who can see and use that thing. There are four levels, from most locked to most open:

  • private means only the same class can use it.
  • default (no keyword) means any class in the same package can use it.
  • protected means the same package, plus any subclass even in another package.
  • public means everything everywhere can use it.
  • β€œdefault” is not a keyword. Write nothing and you get it by accident.
  • Modifiers do not change what a method does. Only who can call it.

πŸ“‹ The access table

Read each row as one modifier, each column as a place that might use the member. A check means allowed.

Modifier Same class Same package Subclass (other package) Everywhere else
private βœ… ❌ ❌ ❌
default βœ… βœ… ❌ ❌
protected βœ… βœ… βœ… ❌
public βœ… βœ… βœ… βœ…

Read top to bottom and the door opens wider each row. private is only the class itself. Each step adds one more group, until public lets in everyone.

A quick way to remember the order

From narrowest to widest the order is private, default, protected, public. Each level can do everything the level above it can do, plus a bit more.

πŸ”’ private: same class only

The private modifier locks a member inside its own class. No other class can see it, not even one in the same file. This is the strongest hiding. Here a class keeps its balance private and offers a safe method to read it.

class BankAccount {
private int balance = 100;
public int getBalance() {
return balance; // βœ… same class, allowed
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
System.out.println(account.getBalance()); // βœ… uses the public method
// System.out.println(account.balance); ❌ won't compile: balance is private
}
}
  • getBalance sits inside BankAccount, so it reads the private field freely.
  • Main is a different class, so the commented line would fail to compile.
  • Outside code must go through the public method, which lets you add rules later.

Output

100

πŸ“¦ default: same package only

When you write no modifier at all, you get default access, also called package-private. The member is visible to any class in the same package, but invisible to classes in other packages. A package is just a folder of related classes. Here two classes share one package.

package shop;
class Product {
String name = "Pen"; // default access, no keyword
}
class Store {
void show() {
Product p = new Product();
System.out.println(p.name); // βœ… same package, allowed
}
}
  • name has no modifier, so it is default.
  • Store lives in the same shop package, so it reads name directly.
  • A class in a different package could not.
  • This is the level you get without trying, which is why it is easy to use by mistake.

πŸ›‘οΈ protected: same package plus subclasses

The protected modifier opens the member to the same package, and also to any subclass, even one in a completely different package. A subclass is a class that extends another with the extends keyword. Here a subclass reaches a protected field from its parent.

class Animal {
protected String name = "Generic";
}
class Dog extends Animal {
void speak() {
System.out.println(name + " says woof"); // βœ… subclass, allowed
}
}
public class Main {
public static void main(String[] args) {
new Dog().speak();
}
}
  • name is protected, so the child class Dog uses it as if it were its own.
  • Reach for protected when you build a class meant to be extended.
  • It lets children share an inner detail without exposing it to the whole program.

Output

Generic says woof

🌍 public: everywhere

The public modifier removes the door entirely. A public member is reachable from any class in any package. Use it for the parts of your class you want everyone to call. Here a public method is used from outside its class.

class Calculator {
public int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(2, 3)); // βœ… public, allowed from anywhere
}
}
  • add is public, so Main calls it freely even though it is a separate class.
  • Public is right for your class’s main features, the methods others rely on.
  • It is wrong for inner details you might want to change later.

Output

5

πŸ›οΈ Modifiers on classes vs members

So far we used modifiers on fields and methods. They also go on classes, but with one important limit.

  • A top-level class (one written directly in a file, not inside another class) can only be public or default. It cannot be private or protected.
  • A member (field, method, or a class nested inside another class) can use all four levels.

Here is the class rule in code.

public class Service { // βœ… public top-level class
}
class Helper { // βœ… default top-level class, used inside the same package
}
// private class Secret {} ❌ a top-level class cannot be private
  • A public top-level class can be used from anywhere. A default one stays inside its package.
  • private and protected only make sense relative to a class or package boundary.
  • A top-level class is already the outermost thing in its file, so those two are not allowed there.

πŸ” How modifiers enforce encapsulation

Encapsulation means hiding the inner data of a class and only exposing safe ways to use it. Access modifiers are the tool that makes it real. The classic pattern is private fields with public methods.

class BankAccount {
private int balance = 0;
public void deposit(int amount) {
if (amount > 0) { // βœ… a rule guards the data
balance += amount;
}
}
public int getBalance() {
return balance;
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.deposit(500);
account.deposit(-100); // ignored, the rule blocks it
System.out.println(account.getBalance());
}
}
  • balance is private, so the only way to change it is through deposit.
  • deposit refuses negative amounts, so the bad value from the first example cannot get in.
  • That is encapsulation: the data is locked, and every change passes a check first.

Output

500

⚠️ Common Mistakes

A few access-modifier habits cause real bugs and leaky designs.

  • Making everything public. It feels easier, but it lets any code change your data with no rules, just like the broken first example.
public int balance; // ❌ anyone can set any value, no checks
private int balance; // βœ… locked, changed only through safe methods
  • Confusing default with public. Leaving off a keyword does not make a member public. It makes it default, visible only inside the package. Code in another package will fail to compile.
class Product { int price; } // ❌ default: not usable from another package
class Product { public int price; } // βœ… public: usable from anywhere (if you really want that)
  • Using protected when private is enough. Protected opens a member to subclasses and the whole package. If only the class itself needs it, that is too wide.
protected int counter; // ❌ exposed to package and subclasses for no reason
private int counter; // βœ… kept where it belongs
  • Trying to make a top-level class private. Java will not compile it. Top-level classes are only public or default.

βœ… Best Practices

Good defaults that keep your classes safe and easy to change.

  • Follow least privilege. Give each member the smallest access it can have and still work. Start with private and open up only when something outside genuinely needs it.
  • Keep fields private. Almost always make fields private and expose them through methods, so every read and write can be controlled.
  • Make only the real features public. Public should be the short list of methods the rest of the program is meant to call, not your inner helpers.
  • Reach for protected only for inheritance. Use it when you are deliberately designing a class to be extended and a child needs the detail.
  • Do not rely on default by accident. If you mean package-private, that is fine, but make it a choice, not a forgotten keyword.

🧩 What You’ve Learned

Nice work. Let’s recap access modifiers.

  • βœ… An access modifier controls who can see and use a class or member.
  • βœ… The four levels, narrowest to widest, are private, default, protected, public.
  • βœ… private is same class only, default is same package, protected adds subclasses, public is everywhere.
  • βœ… Top-level classes can only be public or default; members can use all four.
  • βœ… Private fields with public methods are how access modifiers enforce encapsulation.
  • βœ… Follow least privilege: give the smallest access that still works.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    Which access modifier makes a member visible only inside its own class?

    Why: private limits a member to the same class and nothing else.

  2. 2

    What access do you get when you write no modifier at all?

    Why: No keyword means default access, visible only within the same package.

  3. 3

    Which modifier allows access from a subclass in a different package?

    Why: protected opens a member to the same package plus subclasses anywhere.

  4. 4

    Which levels can a top-level class use?

    Why: A top-level class can only be public or default; private and protected are not allowed there.

πŸš€ What’s Next?

You now know the four levels at a glance. Next we zoom into the one you get without typing anything, the default level, and see exactly how package-private behaves in real code.

Java Default Access Modifier

Share & Connect