CodeGym /Courses /JAVA 25 SELF /Access modifier errors

Access modifier errors

JAVA 25 SELF
Level 23, Lesson 2
Available

1. Introduction

In Java, access modifiers are like the locks in a house. They define who can “enter” your room (or the field/method of your class) and from where. If all the doors are open, anyone can come in and change something. If everything is locked, no one will be able to break anything — but at some point you yourself might find you’re locked in.

Recall that Java has four main access levels:

Modifier Accessible within the class Accessible in the package Accessible in subclasses Accessible in other packages
private
✔
(package) ✔ ✔
protected
✔ ✔ ✔ (via inheritance)
public
✔ ✔ ✔ ✔

(package) is when the modifier is not specified explicitly. Such a class member is visible only within a single package.

2. Typical mistakes with access modifiers

Error 1: Fields and methods with the default modifier (package-private)

The most common mistake beginners make is forgetting to specify an access modifier. As a result, a field or method becomes accessible across the entire package, even though you didn’t plan for that. This can lead to another class (in the same package but unrelated to yours) being able to change your object’s internal state.

// Error: the field name is not protected!
class User {
    String name; // package-private!
}

As a result, any class from this package can write:

User user = new User();
user.name = "John"; // no restrictions!

Error 2: Breaking encapsulation — public fields (public)

The second most popular mistake is declaring class fields as public. It’s convenient when you’re just learning or writing a short example, but in real projects this is almost always bad. You lose control over who changes your data and how.

public class Account {
    public double balance; // DANGEROUS!
}

Now any code can do:

Account acc = new Account();
acc.balance = -1000000; // And who’s to blame now?

Error 3: Missing getters and setters

Sometimes a developer makes fields private but forgets to add methods to manage them. As a result, it’s impossible to get or change the value even where it would be appropriate.

public class Product {
    private String name;
    // Neither getName() nor setName()
}

Error 4: Trying to access private members from another class

If you declared a field or method as private, you cannot access it from another class, even if it’s in the same package. Beginners are often surprised why the field is “not visible.”

public class User {
    private String password;
}

public class UserService {
    public void resetPassword(User user) {
        // user.password = "123"; // Compilation error!
    }
}

Error 5: Mistakes with protected

Many believe that protected means “visible everywhere there is inheritance.” But in Java, access to protected members outside the package is only possible through inheritance and only for the subclass. This nuance is easy to miss.

package animals;

public class Animal {
    protected void sleep() {}
}

package zoo;
import animals.Animal;

public class Dog extends Animal {
    public void test() {
        sleep(); // OK — subclass
    }
}

public class NotADog {
    public void test() {
        Animal a = new Animal();
        // a.sleep(); // Error: not a subclass!
    }
}

3. How to do it right: Best practices

Rule 1: Make fields private by default

This is the core principle of encapsulation. Fields must be hidden from everyone except the class itself. If you need to grant access, use getters/setters.

public class Book {
    private String title;
    private int pages;

    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

Rule 2: Expose only the methods you need

If a method must be accessible from outside — make it public. If it’s needed only within the package — leave it package-private. If a method is intended only for subclasses — use protected.

Rule 3: Minimize visibility

The smaller the visibility scope, the lower the chance of accidental errors and “unexpected guests.” Don’t make methods and fields public unless it’s necessary.

Rule 4: Use getters and setters for access control

This lets you add extra logic when reading/writing a field, for example, validation.

public class Account {
    private double balance;

    public void setBalance(double balance) {
        if (balance < 0) {
            throw new IllegalArgumentException("Balance cannot be negative!");
        }
        this.balance = balance;
    }

    public double getBalance() {
        return balance;
    }
}

Rule 5: Don’t expose internal implementation

If you have an array or a list as a field, don’t return it directly via a getter — return a copy or provide only the methods you need.

public class Team {
    private List<String> members = new ArrayList<>();

    // Correct:
    public List<String> getMembers() {
        return new ArrayList<>(members); // return a copy
    }
}

4. Practical examples

Suppose we have a class LibraryUser that describes a library user.

Incorrect implementation example

public class LibraryUser {
    public String name;
    public int borrowedBooks;
}

In this form, any code can do whatever it wants with the object:

LibraryUser user = new LibraryUser();
user.name = null;
user.borrowedBooks = -10; // Logic? What logic?

Correct implementation example with encapsulation

public class LibraryUser {
    private String name;
    private int borrowedBooks;

    public LibraryUser(String name) {
        this.name = name;
        this.borrowedBooks = 0;
    }

    public String getName() {
        return name;
    }

    public int getBorrowedBooks() {
        return borrowedBooks;
    }

    public void borrowBook() {
        borrowedBooks++;
    }

    public void returnBook() {
        if (borrowedBooks > 0) {
            borrowedBooks--;
        }
    }
}

Now outside code cannot directly change the number of borrowed books or the user’s name. Everything is controlled only through the class’s methods.

5. Implementation specifics and nuances

Sometimes it seems simpler to make a field public than to write a bunch of getters and setters. But that’s a trap! An open field is like an open door to an apartment: yes, it’s convenient, but it’s not very safe.

Another nuance — you don’t always need getters and setters for all fields. If a field’s value shouldn’t change after the object is created, provide only a getter, and make the field final:

public class Passport {
    private final String number;

    public Passport(String number) {
        this.number = number;
    }

    public String getNumber() {
        return number;
    }
}

Also remember: if a class is declared public, the file name must match the class name! This isn’t exactly about access modifiers, but it’s a very common rookie mistake.

6. Typical mistakes when working with access modifiers

Error #1: you forgot to specify an access modifier on a field or method. As a result, the field or method becomes accessible across the entire package, even if you didn’t intend it. Always specify the modifier explicitly, even if the IDE doesn’t complain.

Error #2: all fields are declared public. This kills encapsulation, making your code vulnerable and unpredictable. The “for simplicity” habit from examples must not make it into production code.

Error #3: attempting to access a private field from another class. Java won’t allow this — the compiler will protect you, but if you suddenly want to “work around” it via reflection, think about why you needed that at all.

Error #4: expecting that protected members will be accessible everywhere there’s inheritance. In reality, outside the package they can be accessed only from a subclass and only via this or via a subclass object.

Error #5: returning an internal collection via a getter. If you return a reference to an internal array or list, outside code will be able to modify it, violating the class’s invariants.

Error #6: no validation when setting a value via a setter. If you don’t validate the incoming value, you can end up with an invalid object state (for example, a negative balance).

Error #7: overly broad method visibility. Sometimes methods are made public even though they’re only needed inside the package or class. This exposes unnecessary API and complicates maintenance.

1
Task
JAVA 25 SELF, level 23, lesson 2
Locked
Simple Car Dealership Registry 🚗
Simple Car Dealership Registry 🚗
1
Task
JAVA 25 SELF, level 23, lesson 2
Locked
Secure price management in an online store 💰
Secure price management in an online store 💰
1
Task
JAVA 25 SELF, level 23, lesson 2
Locked
Password Protection: No Backdoors! 🔐
Password Protection: No Backdoors! 🔐
1
Task
JAVA 25 SELF, level 23, lesson 2
Locked
Who can "speak" at the zoo? 🐾
Who can "speak" at the zoo? 🐾
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION