In this short article you can see what’s waiting for you behind the protected Java keyword.

Quick reminder

Table below presents which access rights are granted for another classes using the specific keywords:

ModifierClassPackageSubclassWorld
publicYYYY
protectedYYYN
(default)*YYNN
privateYNNN
* default means no keyword

We will focus now only on the default and protected access modifiers. Default access means that method or field can be accessed only by the classes in the same package. Protected is like default access plus it allows their subclasses from different packages to access class elements marked with protected keyword.

Below is the structure of our example project:

First Animal class:

package example.a;

public class Animal {
    protected String name = "Spike";
    protected void showName() {
        System.out.println(name);
    }
}

And AnimalGreeter which is in the same package, which means that we can use showName() and name:

package example.a;

public class AnimalGreeter {
    public void greetAnimal() {
        Animal animal = new Animal();
        animal.showName();
        System.out.println(animal.name);
    }
}

Horse class which is in a different package and extends Animal:

package example.b;

import example.a.Animal;

public class Horse extends Animal {
    public void greet() {
        showName();
        System.out.println(name);
    }
}

showName() method and name property can be easily accessed and this code compiles.

Now it’s time for AnimalGreeterFromPackageD which is in another package and does not extend the Animal class:

package example.d;

import example.a.Animal;

public class AnimalGreeterFromPackageD {
    public void greetAnimal() {
        Animal animal = new Animal();
        animal.showName(); // Does not compile
        System.out.println(animal.name); // Does not compile
    }
}

Lines 8 and 9 will not compile as AnimalGreeterFromPackageD doesn’t have an access to Animal class methods or properties marked as protected. There are only 2 options to make AnimalGreeterFromPackageD access them:

  1. AnimalGreeterFromPackageD can be moved to the same package as the Animal class – example.a
  2. Animal showName() and name could be changed to public

Now let’s see the last class Dog:

package example.c;

import example.a.Animal;

public class Dog extends Animal {
    public void greet() {
        showName();
        System.out.println(name);
    }

    public void greetAnotherDog() {
        Dog anotherDog = new Dog();
        anotherDog.showName();
        System.out.println(anotherDog.name);
    }

    public void greetAnotherAnimal() {
        Animal anotherAnimal = new Animal();
        anotherAnimal.showName(); // Does not compile
        System.out.println(anotherAnimal.name); // Does not compile
    }
}

Dog is in an another package, but it extends the Animal class. So lines 7-8 and 13-14 compile without problem. But… even if it extends the Animal class, lines 19 and 20 will not compile! This is because the Animal reference created at line 18 comes from an another package and protected access through inheritance does not apply here.

Quirky, isn’t it? For me it wasn’t obvious at a first sight, fortunately IDE will not allow you to write this code. Still it’s a good thing to know this for Java exam or maybe someone will ask you about this as an interview question.