Swiftorial Logo
Home
Swift Lessons
AI Tools
Learn More
Career
Resources

Java FAQ: Top Questions

6. What are Java access modifiers?

Java access modifiers are keywords that set the accessibility (or visibility) level of classes, fields (variables), methods, and constructors. They are a fundamental part of Java's encapsulation mechanism, allowing developers to control which parts of their code can be accessed from other parts of the program. This helps in achieving data hiding and modularity.

There are four main access modifiers in Java:

  • public:
    • Accessible everywhere. Members (classes, methods, fields, constructors) declared public can be accessed from any other class, regardless of the package they are in.
    • Detailed Explanation: This is the least restrictive access level. When a member is declared public, it means it is fully exposed and intended for use by any other part of the application or even by external libraries. Public members form the public API of a class or package.
    • Example:
      
      // In Package A: com.example.packageA
      
      package com.example.packageA;
      
      public class PublicExample {
          public int publicVariable = 10;
      
          public void publicMethod() {
              System.out.println("This is a public method.");
          }
      }
      
      // In another class in Package A:
      class AnotherClassInA {
          public void testAccess() {
              PublicExample obj = new PublicExample();
              System.out.println("Accessing publicVariable: " + obj.publicVariable); // Accessible
              obj.publicMethod(); // Accessible
          }
      }
      
      // In Package B: com.example.packageB
      // (Requires importing com.example.packageA.PublicExample)
      
      package com.example.packageB;
      import com.example.packageA.PublicExample;
      
      public class TestPublicAccess {
          public static void main(String[] args) {
              PublicExample obj = new PublicExample();
              System.out.println("Accessing publicVariable from another package: " + obj.publicVariable); // Accessible
              obj.publicMethod(); // Accessible
          }
      }
                      

      As seen, publicVariable and publicMethod() are accessible from both classes within the same package and classes in different packages after import.

  • protected:
    • Accessible within the same package and by subclasses (even if the subclass is in a different package).
    • Detailed Explanation: This access level is primarily used for inheritance. A protected member is visible to all classes within its own package. Additionally, any class that inherits from the class containing the protected member (regardless of its package) can access that member. It promotes controlled inheritance where subclasses can extend and customize behavior while restricting direct access from unrelated classes outside the package.
    • Example:
      
      // In Package A: com.example.packageA
      
      package com.example.packageA;
      
      public class ProtectedExample {
          protected int protectedVariable = 20;
      
          protected void protectedMethod() {
              System.out.println("This is a protected method.");
          }
      }
      
      class AnotherClassInA_Protected {
          public void testAccess() {
              ProtectedExample obj = new ProtectedExample();
              System.out.println("Accessing protectedVariable (same package): " + obj.protectedVariable); // Accessible
              obj.protectedMethod(); // Accessible
          }
      }
      
      // In Package B: com.example.packageB
      // (Requires importing com.example.packageA.ProtectedExample)
      
      package com.example.packageB;
      import com.example.packageA.ProtectedExample;
      
      class SubclassInB extends ProtectedExample { // Subclass in a different package
          public void testAccess() {
              // Accessing protected members via inheritance
              System.out.println("Accessing protectedVariable (subclass): " + protectedVariable); // Accessible
              protectedMethod(); // Accessible
      
              // Note: You cannot directly access protected members of a ProtectedExample
              // object from *outside* the subclass in a different package.
              // ProtectedExample obj = new ProtectedExample();
              // obj.protectedVariable; // NOT accessible here directly (only through inheritance or in same package)
          }
      }
      
      public class TestProtectedAccess {
          public static void main(String[] args) {
              // Access from unrelated class in different package: NOT ACCESSIBLE
              // ProtectedExample obj = new ProtectedExample();
              // System.out.println(obj.protectedVariable); // Compile-time error
              // obj.protectedMethod(); // Compile-time error
      
              SubclassInB subObj = new SubclassInB();
              subObj.testAccess(); // Calls the method within the subclass, which has access
          }
      }
                      

      The protectedVariable and protectedMethod() are accessible within com.example.packageA and by SubclassInB (which extends ProtectedExample) even though it's in a different package. An unrelated class in packageB cannot directly access them.

  • default (Package-Private):
    • If no access modifier is specified, it's considered default (also known as package-private). Accessible only within the same package.
    • Detailed Explanation: This is the default access level if you don't explicitly use public, protected, or private. Members with default access are only visible to classes within the same Java package. They are not accessible from classes in other packages, even if those classes are subclasses. This is useful for grouping related classes that need to collaborate closely without exposing their internal details to the rest of the application.
    • Example:
      
      // In Package A: com.example.packageA
      
      package com.example.packageA;
      
      class DefaultExample { // Class itself has default access
          int defaultVariable = 30; // Field has default access
      
          void defaultMethod() { // Method has default access
              System.out.println("This is a default (package-private) method.");
          }
      }
      
      class AnotherClassInA_Default {
          public void testAccess() {
              DefaultExample obj = new DefaultExample();
              System.out.println("Accessing defaultVariable (same package): " + obj.defaultVariable); // Accessible
              obj.defaultMethod(); // Accessible
          }
      }
      
      // In Package B: com.example.packageB
      
      package com.example.packageB;
      
      // import com.example.packageA.DefaultExample; // This import would fail if DefaultExample class is not public
      
      public class TestDefaultAccess {
          public static void main(String[] args) {
              // DefaultExample obj = new DefaultExample(); // Compile-time error: DefaultExample is not public
              // System.out.println(obj.defaultVariable); // Compile-time error
              // obj.defaultMethod(); // Compile-time error
              System.out.println("Cannot access default members from another package.");
          }
      }
                      

      defaultVariable and defaultMethod() (and even the DefaultExample class itself) are only accessible from within com.example.packageA. Any class in com.example.packageB will not be able to access them.

  • private:
    • Accessible only within the class where they are declared.
    • Detailed Explanation: This is the most restrictive access level. private members are only visible and accessible from within the class itself. They cannot be accessed from outside the class, not even by subclasses or classes in the same package. This is the cornerstone of encapsulation, allowing a class to hide its internal implementation details and expose only what is necessary through public methods (getters/setters).
    • Example:
      
      // In Package A: com.example.packageA
      
      package com.example.packageA;
      
      public class PrivateExample {
          private int privateVariable = 40; // Private field
      
          private void privateMethod() { // Private method
              System.out.println("This is a private method.");
          }
      
          public void accessPrivateMembers() {
              // Accessible within the same class
              System.out.println("Accessing privateVariable from inside the class: " + privateVariable);
              privateMethod();
          }
      }
      
      class AnotherClassInA_Private {
          public void testAccess() {
              PrivateExample obj = new PrivateExample();
              // System.out.println(obj.privateVariable); // Compile-time error
              // obj.privateMethod(); // Compile-time error
              System.out.println("Cannot directly access private members from outside the class.");
              obj.accessPrivateMembers(); // Accessible via a public method
          }
      }
      
      // In Package B: com.example.packageB
      
      package com.example.packageB;
      import com.example.packageA.PrivateExample;
      
      public class TestPrivateAccess {
          public static void main(String[] args) {
              PrivateExample obj = new PrivateExample();
              // System.out.println(obj.privateVariable); // Compile-time error
              // obj.privateMethod(); // Compile-time error
              System.out.println("Cannot directly access private members from another package.");
              obj.accessPrivateMembers(); // Accessible via a public method
          }
      }
                      

      privateVariable and privateMethod() can only be directly accessed by other methods within the PrivateExample class itself. Any attempt to access them from outside (even from a subclass or a class in the same package) will result in a compile-time error. You need a public method (like accessPrivateMembers()) to expose or modify private data in a controlled manner.

Summary of Access Levels (from most to least restrictive):

Modifier Same Class Same Package (Subclass) Same Package (Non-subclass) Different Package (Subclass) Different Package (Non-subclass)
private
default
protected
public

Choosing the right access modifier is critical for designing robust and maintainable Java applications, as it directly impacts encapsulation and the overall structure of your code.