9.3. Package Private Visibility¶
Instead of saying that something has package private visibility, we usually just say that it’s package private. In Java, only top-level and member-level declarations are allowed to be package private. Entities that are package private are slightly more visible than entities that are private; they are only visible from lines of code in the same package.
Visibility |
Visible From |
|||
---|---|---|---|---|
Name |
Same Class |
Same Package |
Child Class |
Elsewhere |
package private |
Y |
Y |
N |
N |
In Java, there is no modifier keyword for package private visibility. For top-level declarations and member-level declarations within a class, the omission of a visibility modifier will cause the compiler to treat the declared thing as package private. This behavior is different for member-level declarations within an interface, where the omission of a visibility modifier defaults a declaration’s visibility to public.
In UML, the
~
symbol is used just before an identifier to illustrate that it is package private. Some UML programs may not support displaying the visibility for top-level declarations; in those cases, a quick hack is to include the~
as part of the name. Although omitting a visibility modifier in Java code may default to package private, the same is not true for UML class diagrams; they default to public visibility (covered in a later section).The javadoc program does not include package private declarations in a documentation website by default; however, they can be included by adding the
-package
command-line argument (that option will also include anything that is more visible than package private — so everything except private).
Some people refer to package private visibility as the “default visibility” because a modifier isn’t needed to indicate that certain declarations are package private; however, the term “default” should be avoided when describing visibility so that the concept is not confused with Java’s default member-level visibility for interfaces or a completely unrelated concept of default methods in interfaces, the latter being something that is not covered in this text.
Test Yourself
What visibility keyword is used in Java to denote that a declaration is package private?
Review Question
Consider the following directory structure for a project:
cs1302/
├─ models/
│ ├─ Utility.java
│ └─ Person.java
├─ store/
│ └─ Driver.java
└─ main/
└─ App.java
Write the package statements that should appear at the top of each file.
Solution
// Utility.java and Person.java package cs1302.models; // Driver.java package cs1302.store; // App.java package cs1302.main;
Which classes are in the same package?
Solution
Same package:
Utility.java
andPerson.java
(cs1302.models
).Utility.java
has no visibility modifier (package private). Which files can directly access the entities declared withinUtility
?Solution
Only
Person.java
(same packagecs1302.models
) can accessUtility
directly.Driver.java
andApp.java
cannot.Person.java
has a private instance variableprivate String name;
. CanDriver.java
orApp.java
accessname
directly? Why or why not?Solution
No.
name
is private, so it is only accessible withinPerson.java
itself. No external class can access it directly, regardless of package.If a method in
Utility.java
is declared private, can any other class incs1302.models
call it? What about a class incs1302.store
?Solution
Since its a private method, it is only accessible within
Utility.java
. Classes incs1302.models
orcs1302.store
cannot call it.Suppose you accidentally declare
Person
as public instead of package private. Which new classes can now access it directly that could not before?Solution
Declaring
Person
as public allows all classes in all packages (cs1302.store
,cs1302.main
) to access it directly.If
Utility
has a private constructor and only static methods, what is the purpose of making the constructor private? CouldDriver.java
create a newUtility
object? Why or why not?Solution
Private constructor prevents object creation outside the class.
Driver.java
cannot create a newUtility
object; only the class itself can call its constructor (useful for utility classes with static methods).For
App.java
incs1302.main
, which of the following statements are true?It can directly access package private members of
Utility.java
.It can call public static methods of
Utility.java
if it’s imported.It can access private members of
Person.java
after creating an object.
Solution
False – package private not visible outside package.
True – public static methods can be called if class is imported.
False – private members cannot be accessed directly even after object creation.
9.3.1. Example 1¶
Here is our first example involving a top-level declaration. To get started, let’s consider the UML diagram below and the two code snippets that follow it.
NOTE: class Utility
is package private. Unfortunately, the ~ is not
showing up properly in the diagram.
package cs1302.models;
class Utility { // <---- LINE1
// ... rest omitted
package cs1302.store;
import cs1302.models.Utility; // <---- LINE2
// ... rest omitted
On the line labeled LINE1
, the author omitted a visibility
modifier in their top-level declaration of the Utility
class. As
discussed earlier, this causes the class to default to package private
visibility. On LINE2
, which exists in Driver.java
in a
different package [6], an attempt is made to import the Utility
class. Since that class is package private, it’s not visible from this
line because things that are package private are only visible from
within the same package. If you try to compile Driver.java
, then
you get the following error:
Driver.java: Utility is not public in cs1302.models; cannot be accessed from outside package
The error above is exactly what the author of Utility
class wanted
to happen. They intended for Utility
itself to only be used by
code residing within the cs1302.models
package. To make the method
not visible from outside the package, they omitted a visibility
modifier in the top-level class declaration. Had they declared it
public, for example, then the example would have compiled.
As an aside, the UML diagram for this example also includes a private constructor [7]! You can read about it in the footnote.
Test Yourself
When are two classes considered to be in the same package?
When are two classes considered to be in different packages?
9.3.2. Example 2¶
In this example, we’ll see how package private visibility can be used at the member-level for access control. Suppose a factory has a contract with a store to produce some product. Throughout the year, the store may need to request changes to its contract based on sales, buyer interest, etc. The driver program on the factory’s side should be able to access methods to request, approve, and deny contract-related changes; however, the overall class design should not allow for the store to approve or deny changes in this scenario. To see how we can utilize package private visibility to accomplish this, let’s consider the UML diagram below and the two code snippets that follow it.
public static void main(String[] args) {
Factory factory = new Factory();
factory.requestChange("decrease price"); // <------- LINE1
factory.approveChange("decrease price"); // <------- LINE2
factory.denyChange("decrease price"); // <---------- LINE3
} // main
public static void main(String[] args) {
Factory factory = new Factory();
factory.requestChange("increase quantity"); // <---- LINE4
factory.approveChange("increase quantity"); // <---- LINE5
factory.denyChange("increase quantity"); // <------- LINE6
} // main
The lines labeled LINE1
, LINE2
, and LINE3
each attempt
to access a different member of the Factory
class from the same package.
The table below summarizes the scenario for each line.
Class names in the In
and From
columns have been omitted since they’re not
relevant for this particular example.
Member Accessed |
|||||
---|---|---|---|---|---|
LINE |
Name |
Declared |
In |
From |
Visible? |
1 |
|
public |
|
|
Y |
2 |
|
package private |
|
|
Y |
3 |
|
package private |
|
|
Y |
Likewise, the lines labeled LINE4
, LINE5
, and LINE6
each attempt
to access a different member of the Factory
class from a different package.
The table below summarizes the scenario for each line.
Member Accessed |
|||||
---|---|---|---|---|---|
LINE |
Name |
Declared |
In |
From |
Visible? |
4 |
|
public |
|
|
Y |
5 |
|
package private |
|
|
N |
6 |
|
package private |
|
|
N |
If you try to compile Driver.java
as written, then you get the following error:
Driver.java: error: approveChange(String) is not public in Factory; cannot be accessed from outside package
Through careful use of visibility, the author of the Factory
class
was able to achieve the access control described near the beginning of
this example. That is, code within the cs1302.factory
package can
request, approve, and deny contract-related requests, while code in
other packages can only request changes. It’s a beautiful, simple
setup, but it did require the author to understand package private
visibility.
In the error message that was recently discussed, the wording “is not public in” may lead you to believe that only public members are visible from another package; that’s not the case. We’ll provide an example in the next section on protected visibility that illustrates this.
Test Yourself
How can package private visibility be used to limit where the creation of objects takes place?