6.5 Access Modifiers
In this section, we discuss accessibility of top-level type declarations that can be encapsulated into packages and accessibility of members that can be encapsulated in a top-level type declaration. A top-level reference type is a reference type (class, interface, enum, record) that is not declared inside another reference type.
Access modifiers are sometimes also called visibility modifiers.
Access Modifiers for Top-Level Type Declarations
The access modifier public can be used to declare top-level reference types that are accessible from everywhere, both from inside their own package and from inside other packages. If the access modifier is omitted, the reference types can be accessed only in their own package and not in any other packages—that is, they have package access, also called package-private or default access.
The packages shown in Figure 6.2, p. 327, are implemented by the code in Example 6.7. Class files with Java bytecode for top-level type declarations are placed in designated packages using the package statement. A top-level type declaration from one package can be accessed in another packages either by using the fully qualified name of the type or by using an import statement to import the type so that it can be accessed by its simple name.
Example 6.7 Access Modifiers for Top-Level Reference Types
// File: Clown.java
package wizard.pandorasbox; // Package declaration
import wizard.pandorasbox.artifacts.Ailment; // Importing class Ailment
public class Clown implements Magic { // (1)
LovePotion tlc; // Class in same package
Ailment problem; // Simple class name
Clown() {
tlc = new LovePotion(“passion”);
problem = new Ailment(“flu”); // Simple class name
}
@Override public void levitate() { // (2)
System.out.println(“Levitating”);
}
public void mixPotion() { System.out.println(“Mixing ” + tlc); }
public void healAilment() { System.out.println(“Healing ” + problem); }
public static void main(String[] args) {
Clown joker = new Clown();
joker.levitate();
joker.mixPotion();
joker.healAilment();
}
}
interface Magic { void levitate(); } // (3)
// File: LovePotion.java
package wizard.pandorasbox; // Package declaration
public class LovePotion { // (4) Accessible outside package
String potionName;
public LovePotion(String name) { potionName = name; }
public String toString() { return potionName; }
}
// File: Ailment.java
package wizard.pandorasbox.artifacts; // Package declaration
public class Ailment { // Accessible outside package
String ailmentName;
public Ailment(String name) { ailmentName = name; }
public String toString() { return ailmentName; }
}
// File: Baldness.java
package wizard.spells; // Package declaration
import wizard.pandorasbox.*; // Redundant
import wizard.pandorasbox.artifacts.*; // Import of subpackage
public class Baldness extends Ailment { // Simple name for Ailment
wizard.pandorasbox.LovePotion tlcOne; // Fully qualified name
LovePotion tlcTwo; // Class in same package
Baldness(String name) {
super(name);
tlcOne = new wizard.pandorasbox. // Fully qualified name
LovePotion(“romance”);
tlcTwo = new LovePotion(); // Class in same package
}
}
class LovePotion /* implements Magic */ { // (5) Magic is not accessible
// @Override public void levitate() {} // (6) Cannot override method
}
Compiling and running the program from the current directory gives the following results:
>
javac -d . Clown.java LovePotion.java Ailment.java Baldness.java
>
java wizard.pandorasbox.Clown
Levitating
Mixing passion
Healing flu
In Example 6.7, the class Clown at (1) and the interface Magic at (3) are placed in a package called wizard.pandorasbox. The public class Clown is accessible from everywhere. The Magic interface has package accessibility, and can only be accessed within the package wizard.pandorasbox. It is not accessible from other packages, not even from subpackages.
The class LovePotion at (4) is also placed in the package called wizard.pandorasbox. The class has public accessibility, and is therefore accessible from other packages. The two files Clown.java and LovePotion.java demonstrate how several compilation units can be used to group classes in the same package, as the type declarations in these two source files are placed in the package wizard.pandorasbox.
In the file Clown.java, the class Clown at (1) implements the interface Magic at (3) from the same package. We have used the annotation @Override in front of the declaration of the levitate() method at (2) so that the compiler can aid in checking that this method is declared correctly as required by the interface Magic.
In the file Baldness.java, the class LovePotion at (5) wishes to implement the interface Magic at (3) from the package wizard.pandorasbox, but this is not possible, although the source file imports from this package. The reason is that the interface Magic has package accessibility, and can therefore only be accessed within the package wizard.pandorasbox. The method levitate() of the Magic interface therefore cannot be overridden in class LovePotion at (6).
Table 6.2 summarizes accessibility of top-level reference types in a package. Just because a reference type is accessible does not necessarily mean that members of the type are also accessible. Accessibility of members is governed separately from type accessibility, as explained in the next subsection.
Table 6.2 Access Modifiers for Top-Level Reference Types (Non-Modular)
Modifiers | Top-level types |
No modifier | Accessible in its own package (package accessibility) |
public | Accessible anywhere |