Java
encapsulation
access modifiers
package-private
software design

Making certain methods visible only to particular packages

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, the closest thing to "visible only inside this package" is package-private access, created by leaving off an access modifier. What Java does not support is visibility for an arbitrary hand-picked list of packages, so if that is the goal, the real answer is usually a package or module design change rather than a new keyword.

The Access Levels That Matter

For this problem, the useful Java access levels are:

  • 'public, visible everywhere'
  • 'protected, visible in the same package and in subclasses'
  • package-private, visible only in the same declared package
  • 'private, visible only inside the declaring class'

Package-private is the normal tool for internal collaboration inside one package.

How Package-Private Works

You create package-private visibility simply by omitting the modifier:

java
1package com.example.internal;
2
3public class Validator {
4    void validateState() {
5        System.out.println("Only visible in this package");
6    }
7}

Another class in the same package can call the method:

java
1package com.example.internal;
2
3public class Runner {
4    public static void main(String[] args) {
5        Validator validator = new Validator();
6        validator.validateState();
7    }
8}

But a class in a different package cannot:

java
1package com.example.api;
2
3import com.example.internal.Validator;
4
5public class ExternalUse {
6    public static void main(String[] args) {
7        Validator validator = new Validator();
8        // validator.validateState();
9    }
10}

The commented line fails to compile because the method is not visible outside com.example.internal.

What Java Cannot Express

Java does not provide a syntax for rules like:

  • visible to package a.b.c and x.y.z only
  • visible to sibling packages but not other packages
  • visible to one package tree except a few others

That type of allowlist-style visibility does not exist at the language level. The built-in boundary is the declaring package, not a customizable set of packages.

Design Around the Package Boundary

If several classes need internal access, place them in the same package and expose a smaller public API from a different package.

A common structure looks like:

  • 'com.example.api for public entry points'
  • 'com.example.internal for package-private collaborators'

That keeps internal details hidden from outside callers without introducing artificial public methods just to satisfy package layout mistakes.

Why protected Usually Does Not Help

Many developers reach for protected when they mean "internal." That is usually wrong.

protected means:

  • visible in the same package
  • also visible to subclasses, even if they live elsewhere

So protected is about inheritance, not package friendship. If subclass access is not part of your design, protected often makes the surface area broader than intended.

Modules Change the Package Story, Not Per-Method Friendship

Modern Java also has the module system. Modules let you choose which packages are exported to other modules and which packages stay encapsulated. That can improve large-scale visibility rules, but it still does not let you say "this one method is visible to these two packages only."

So the practical options remain:

  • use package-private for package-local internals
  • reorganize packages if the current boundary is wrong
  • use modules to control exported packages at a higher level

Testing Considerations

Package-private methods are often convenient for tests that live in the same package. If your tests are in a separate package and need direct access, that may indicate one of two things:

  • the test should go through the public API instead
  • the package boundary is not aligned with how the code collaborates

Making a method public just for tests often leaves a permanent API scar in the production codebase.

A Practical Rule of Thumb

If you want a method visible only to a small cluster of cooperating classes, ask:

  1. should those classes be in the same package
  2. should the internal logic move behind a package-private helper
  3. should the real API be a smaller public façade

That line of thinking is usually more productive than searching for a non-existent "friend package" feature.

Common Pitfalls

  • Expecting Java to support arbitrary per-package allowlists for method visibility.
  • Using public just to make cross-package collaboration easy weakens encapsulation.
  • Using protected as a substitute for package friendship exposes methods to subclasses too.
  • Confusing filesystem folder layout with Java package visibility rules.
  • Leaving tightly coupled internal classes scattered across unrelated packages creates pressure for unnecessary public APIs.

Summary

  • In Java, package-private access is created by omitting the modifier.
  • Package-private methods are visible only inside the same declared package.
  • Java does not support visibility to an arbitrary subset of chosen packages.
  • 'protected is about inheritance plus same-package access, not friend-package access.'
  • If the visibility rule feels awkward, the package structure is often the real thing that needs redesign.

Course illustration
Course illustration

All Rights Reserved.