NBKRIST – Java Hub

Java Package Access Demo

Expert Insights on Package Access Control

As a software engineer, I often emphasize that understanding package access is not just about knowing keywords like public or protected β€” it’s about mastering how information is controlled and shared across modular boundaries. Package-level access is the first line of defense in ensuring code security, maintainability, and data encapsulation.

Before diving into how packages are built, it’s critical to understand how and when classes, methods, or variables can be seen or hidden from other parts of an application. This understanding forms the foundation of robust software design β€” ensuring that the right modules interact while sensitive components stay secure.

When properly used, access control through packages prevents accidental misuse, strengthens abstraction, and establishes clear boundaries of communication between components β€” a principle that scales from academic projects to real-world enterprise systems.

Role of Protected and Other Modifiers

The protected modifier in Java is particularly powerful because it enables controlled inheritance across package boundaries. While private ensures strict internal encapsulation, default allows visibility within the same package, and public provides open access globally β€” protected acts as a bridge between security and reusability.

In multi-package architectures, protected members can be inherited but not directly accessed by unrelated classes in other packages. This balance of visibility allows extensibility without compromising integrity, making it a cornerstone of object-oriented software engineering.

Class Definitions

// File: org/edu/nbkrist/cse/protect/Protection.java

package org.edu.nbkrist.cse.protect;

public class Protection { int n = 1; private int n_pri = 2; protected int n_pro = 3; public int n_pub = 4;

public Protection() { System.out.println("base constructor"); System.out.println("n = " + n); System.out.println("n_pri = " + n_pri); System.out.println("n_pro = " + n_pro); System.out.println("n_pub = " + n_pub); } }
// File: org/edu/nbkrist/cse/protect/Derived.java

package org.edu.nbkrist.cse.protect;

public class Derived extends Protection { public Derived() { System.out.println("derived constructor"); System.out.println("n = " + n); System.out.println("n_pro = " + n_pro); System.out.println("n_pub = " + n_pub); } }
// File: org/edu/nbkrist/cse/protect/SamePackage.java

package org.edu.nbkrist.cse.protect;

public class SamePackage { public SamePackage() { Protection p = new Protection(); System.out.println("n = " + p.n); System.out.println("n_pro = " + p.n_pro); System.out.println("n_pub = " + p.n_pub); } }
// File: org/edu/nbkrist/cse/protect2/Protection2.java

package org.edu.nbkrist.cse.protect2;

import org.edu.nbkrist.cse.protect.*;

public class Protection2 extends Protection { public Protection2() { System.out.println("Protection2 constructor"); System.out.println("n_pro = " + n_pro); System.out.println("n_pub = " + n_pub); } }
// File: org/edu/nbkrist/cse/protect2/OtherPackage.java

package org.edu.nbkrist.cse.protect2;

import org.edu.nbkrist.cse.protect.*;

public class OtherPackage { public OtherPackage() { System.out.println("OtherPackage constructor"); Protection p = new Protection(); System.out.println("n_pub = " + p.n_pub); } }

Test Class & Output

// File: org/edu/nbkrist/cse/main/ProtectionTest.java

package org.edu.nbkrist.cse.main;

import org.edu.nbkrist.cse.protect.*; import org.edu.nbkrist.cse.protect2.*;

public class ProtectionTest { public static void main(String[] args) { System.out.println("Testing Protection class"); Protection p = new Protection(); Derived d = new Derived(); SamePackage sp = new SamePackage(); Protection2 p2 = new Protection2(); OtherPackage op = new OtherPackage(); } }

Output:

Testing Protection class
base constructor
n = 1
n_pri = 2
n_pro = 3
n_pub = 4
derived constructor
n = 1
n_pro = 3
n_pub = 4
n = 1
n_pro = 3
n_pub = 4
Protection2 constructor
n_pro = 3
n_pub = 4
OtherPackage constructor
n_pub = 4