Java Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

In the Java programming language, fields, constructors, methods, and classes can be marked with access modifiers. In this tutorial, we'll look at protected access.

2. The protected Keyword

While elements declared as private can be accessed only by the class in which they're declared, the protected keyword allows access from sub-classes and members of the same package.

By using the protected keyword, we make decisions about which methods and fields should be considered internals of a package or class hierarchy, and which are exposed to outside code.

3. Declaring protected Fields, Methods, and Constructors

First, let's create a class named FirstClass containing a protected field, method, and constructor:

public class FirstClass {

    protected String name;

    protected FirstClass(String name) {
        this.name = name;
    }

    protected String getName() {
        return name;
    }
}

With this example, by using the protected keyword, we've granted access to these fields to classes in the same package as FirstClass and to sub-classes of FirstClass.

4. Accessing protected Fields, Methods, and Constructors

4.1 From the Same Package

Now, let's see how we can access protected fields by creating a new GenericClass declared in the same package as FirstClass:

public class GenericClass {

    public static void main(String[] args) {
        FirstClass first = new FirstClass("random name");
        System.out.println("FirstClass name is " + first.getName());
        first.name = "new name";
    }
}

As this calling class is in the same package as FirstClass, it's allowed to see and interact with all the protected fields, methods, and constructors.

4.2. From a Different Package

Let's now try to interact with these fields from a class declared in a different package from FirstClass:

public class SecondGenericClass {

    public static void main(String[] args) {
        FirstClass first = new FirstClass("random name");
        System.out.println("FirstClass name is "+ first.getName());
        first.name = "new name";
    }
}

As we can see, we get compilation errors:

The constructor FirstClass(String) is not visible
The method getName() from the type FirstClass is not visible
The field FirstClass.name is not visible

That's exactly what we were expecting by using the protected keyword.  This is because SecondGenericClass is not in the same package as FirstClass and does not subclass it.

4.3 From a Sub-Class

Let's now see what happens when we declare a class extending FirstClass but declared in a different package:

public class SecondClass extends FirstClass {
    
    public SecondClass(String name) {
        super(name);
        System.out.println("SecondClass name is " + this.getName());
        this.name = "new name";
    } 
}

As expected, we can access all the protected fields, methods, and constructors. This is because SecondClass is a sub-class of FirstClass.

5. protected Inner Class

In the previous examples, we saw protected fields, methods, and constructors in action. There is one more particular case — a protected inner class.

Let's create this empty inner class inside our FirstClass:

package com.baeldung.core.modifiers;

public class FirstClass {

    // ...

    protected static class InnerClass {

    }
}

As we can see, this is a static inner class, and so can be constructed from outside of an instance of FirstClass. However, as it is protected, we can only instantiate it from code in the same package as FirstClass.

5.1 From the Same Package

To test this, let's edit our GenericClass:

public class GenericClass {

    public static void main(String[] args) {
        // ...
        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }
}

As we can see, we can instantiate the InnerClass without any problem because GenericClass is in the same package as FirstClass.

5.2. From a Different Package

Let's try to instantiate an InnerClass from our SecondGenericClass which, as we remember, is outside FirstClass' package:

public class SecondGenericClass {

    public static void main(String[] args) {
        // ...

        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }
}

As expected, we get a compilation error:

The type FirstClass.InnerClass is not visible

5.3. From a Sub-Class

Let's try to do the same from our SecondClass:

public class SecondClass extends FirstClass {
    
    public SecondClass(String name) {
        // ...
 
        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }     
}

We were expecting to instantiate our InnerClass with ease. However, we are getting a compilation error here too:

The constructor FirstClass.InnerClass() is not visible

Let's take a look at our InnerClass declaration:

protected static class InnerClass {
}

The main reason we are getting this error is that the default constructor of a protected class is implicitly protected. In addition, SecondClass is a sub-class of FirstClass but is not a sub-class of InnerClass.  Finally, we also declared SecondClass outside FirstClass' package.

For all these reasons, SecondClass can't access the protected InnerClass constructor.

If we wanted to solve this issue and allow our SecondClass to instantiate an InnerClass object, we could explicitly declare a public constructor:

protected static class InnerClass {
    public InnerClass() {
    }
}

By doing this, we no longer get a compilation error, and we can now instantiate an InnerClass from SecondClass.

6. Conclusion

In this quick tutorial, we discussed the protected access modifier in Java. With it, we can ensure exposing only the required data and methods to sub-classes and classes in the same package.

As always, the example code is available over on GitHub.

Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

Leave a Reply

avatar
  Subscribe  
Notify of