In Java, any variable, class, or method can be modified with a keyword that determines its visibility to other classes. These are known as access modifiers and there are four choices (ordered from most to least restrictive): private, default (no modifier), protected, and public.
Let’s take a look at each of these access modifiers to understand the differences between them.
To explain Java access modifiers, we will reference this code example:
package example; public class NPC { private int level; boolean stuck; protected int health; public boolean alive; public NPC(int level, boolean stuck, int health, boolean alive) { this.level = level; this.stuck = stuck; this.health = health; this.alive = alive; } }
Here, our NPC
class has four properties, each with a different access modifier. Now we can extend the example to show the visibility scope for each of these.
Consider this code snippet:
import example.NPC; public class Game { public static void main(String[] args) { NPC npc = new NPC(10, false, 100, true); npc.level = 11; } }
We declared the level
property as private
in our example, so it is accessible and modifiable within the NPC
class. However, the property will not be visible to any other class. When trying to compile the above Game
class, we will get following compilation error:
Game.java:7: error: level has private access in NPC npc.level = 11; ^ 1 error error: compilation failed
Any change to the level
property must, therefore, be done within the NPC
class, like this:
package example; public class NPC { private int level; boolean stuck; protected int health; public boolean alive; public NPC(int level, boolean stuck, int health, boolean alive) { this.level = level; this.stuck = stuck; this.health = health; this.alive = alive; } public void levelUp() { this.level += 1; System.out.println("NPC is now level " + level); } }
import example.NPC; public class Game { public static void main(String[] args) { NPC npc = new NPC(10, false, 100, true); npc.levelUp(); } }
Output:
NPC is now level 11
In our code example, the stuck
property does not have an access modifier. This is the default option in Java and is also referred to as package-private.
package example; public class Wall { public void block(NPC npc) { npc.stuck = true; System.out.println("NPC is now stuck"); } }
Here, the Wall
class – which is in the same package as the NPC
class – can access and modify the stuck
property. However, as with the private access modifier, this property is not visible to classes outside of its package.
package example; public class Wall { public void block(NPC npc) { npc.stuck = true; System.out.println("NPC is now stuck"); } }
import example.*; public class Game { public static void main(String[] args) { NPC npc = new NPC(10, false, 100, true); Wall wall = new Wall(); wall.block(npc); } }
Output:
NPC is now stuck
The protected modifier is generally considered to be the most complex of the bunch. It is similar to the default modifier in that any class within the same package has access. However, the protected modifier extends visibility to any child class, even those outside the package. This is illustrated below with the health
attribute and the boss
class.
package boss; import example.NPC; public class Boss extends NPC { public Boss(int level, boolean stuck, int health, boolean alive) { super(level, stuck, health, alive); } public void bossMode() { this.health = 1000; System.out.println("Boss now has " + this.health + " health! Good Luck"); } }
import boss.Boss; public class Game { public static void main(String[] args) { Boss npc = new Boss(10, false, 100, true); npc.bossMode(); } }
Output:
Boss now has 1000 health! Good Luck
Both the default and protected access modifiers can be confusing for programmers with backgrounds in C++ or similar. In these languages, the protected
modifier restricts visibility to child classes, and the default access modifier is equivalent to the private
option in Java.
The public access modifier is more straightforward. Any class within the Java project has full access to properties or methods modified with the public access modifier. We have already been using public methods in previous examples, but let’s refer to the alive
property from the above NPC
example to make it more specific:
import example.NPC; public class Game { public static void main(String[] args) { NPC npc = new NPC(10, false, 100, true); if (npc.alive) { System.out.println("The NPC lives!"); } } }
Output:
The NPC lives!
Here’s a table to summarize visibility based on the assigned access modifier:
Private | Default | Protected | Public | |
---|---|---|---|---|
Project | X | X | X | ✓ |
Subclass different package | X | X | ✓ | ✓ |
Subclass same package | X | ✓ | ✓ | ✓ |
Class | ✓ | ✓ | ✓ | ✓ |