TL;DR - The protected access modifier provides a level of access that is broader than package-private (i.e. Java default access modifier) but more restricted than public.

  • protected: accessible from classes within the same package and subclasses (i.e. inherited)
  • package-private: accessible from classes within the same package

Example to illustrate protected access

CodeCreator.java

package com.example.cc;

abstract class CodeCreator {
    // Protected abstract method
    protected abstract void createCode();

    // Protected concrete method
    protected void startCreating() {
        System.out.println("Starting the code creation process...");
    }
}

Developer.java

package com.example.cc;

public class Developer extends CodeCreator {
    private String name;
    private String language;

    // Constructor
    public Developer(String name, String language) {
        this.name = name;
        this.language = language;
    }

    // Getter for name
    public String getName() {
        return name;
    }

    // Setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Getter for language
    public String getLanguage() {
        return language;
    }

    // Setter for language
    public void setLanguage(String language) {
        this.language = language;
    }

    // Implementation of the abstract method
    @Override
    protected void createCode() {
        System.out.println(name + " is coding in " + language + ".");
    }

    // Example method
    public void code() {
        startCreating(); // Calling a protected method from the parent class
        createCode(); // Calling the overridden protected abstract method
    }
}

In this case, any classes within the same package could access createCode and startCreating methods of CodeCreator or Developer. Moreover, as these methods are protected, subclasses of CodeCreator (e.g. Developer) can also access and override these protected methods even if the subclasses were to be in a different packages.

The key idea is that we cannot call a protected method in a non-subclass that is under a different package as where that particular method is defined.

package com.example.base;

public class BaseClass {
    protected void protectedMethod() {
        System.out.println("This is a protected method.");
    }
    
    void packagePrivateMethod() {
        System.out.println("This is a package-private method.");
    }
}

package com.example.sub;

import com.example.base.BaseClass;

public class SubClass extends BaseClass {
    public void accessMethods() {
        protectedMethod(); // Accessible because SubClass extends BaseClass
        // packagePrivateMethod(); // Not accessible because it's package-private and SubClass is in a different package
    }
}

package com.example.other;

import com.example.base.BaseClass;

public class OtherClass {
    public void tryToAccess() {
        BaseClass base = new BaseClass();
        // base.protectedMethod(); // Not accessible because OtherClass does not extend BaseClass and is in a different package
        // base.packagePrivateMethod(); // Not accessible because it's package-private and OtherClass is in a different package
    }
}