9.2. Public and Private Visibility¶
9.2.1. Public Visibility¶
Instead of saying that something has public visibility, we usually just say that it is public. In Java, only top-level and member-level declarations are allowed to be public. Things that are public are considered to be the most visible; they are always visible.
Visibility |
Visible From |
|||
|---|---|---|---|---|
Name |
Same Class |
Same Package |
Child Class |
Elsewhere |
public |
Y |
Y |
Y |
Y |
In Java, the
publicmodifier must be included in a declaration for it to be considered public by the compiler.In UML, the
+symbol is used just before a member’s identifier to illustrate that it is public. It is also common practice to assume that a class in a UML class diagram is public if no visibility symbol is included.The javadoc program includes public declarations in a documentation website by default. If you want javadoc to only include public declarations, then the
-publiccommand-line argument can be used.
Review Question
Consider the following class:
1/**
2* Represents a bank account with a balance.
3*/
4public class BankAccount {
5
6 // public instance variable
7 public double balance;
8
9 /**
10 * Constructs a BankAccount with the specified balance.
11 *
12 * @param balance the initial balance of the account
13 */
14 public BankAccount(double balance) {
15 this.balance = balance;
16 } // BankAccount
17
18} // BankAccount
Can code outside this class directly modify
balance?Solution
Yes. Any code can directly read or modify the
balancevariable because it is public.Why might making
balancepublic be a bad idea in terms of encapsulation?Solution
Making instance variables public is generally a bad idea because it allows any code to read or modify them directly, which can lead to invalid or inconsistent states (like a negative balance). This breaks encapsulation, since the class cannot enforce rules or control how its internal data is changed.
How could you redesign this class to allow controlled access to
balancewhile keeping it safe?Solution
Make
balanceprivate and provide getter and setter methods that include validation like the code below. This preserves control over howbalanceis modified.1private double balance; 2 3/** 4 * Returns the current balance of this account. 5 * 6 * @return the balance 7 */ 8public double getBalance() { 9 return balance; 10} // getBalance 11 12/** 13 * Deposits the specified amount into this account. 14 * Only positive amounts are allowed. 15 * 16 * @param amount the amount to deposit 17 */ 18public void deposit(double amount) { 19 if (amount > 0) { 20 balance += amount; 21 } // if 22} // deposit
9.2.2. Private Visibility¶
Instead of saying that something has private visibility, we usually just say that it is private. In Java, only member-level declarations are allowed to be private. Private members are considered the least visible; they are only visible from lines of code in the same class.
Visibility |
Visible From |
|||
|---|---|---|---|---|
Name |
Same Class |
Same Package |
Child Class |
Elsewhere |
private |
Y |
N |
N |
N |
In Java, the
privatemodifier must be included in a member’s declaration for it to be considered private by the compiler.In UML, the
-symbol is used just before a member’s identifier to illustrate that it is private.The javadoc program does not include private declarations in a documentation website by default; however, they can be included by adding the
-privatecommand-line argument (that option will also include anything that is more visible than private — therefore, it will include everything).
Test Yourself
What kinds of declarations can have private visibility in Java?
What is the full javadoc command (not just the option) to generate an API documentation website for a Java package that will result in private declarations being included in the generated website?
9.2.3. Example 1¶
This is a classic example that many students are familiar with. To get started, let us consider the UML diagram below and the code snippet that follows it.
public void setAge(int age) {
if (!checkAge(age)) { // <---- LINE1 ✓
throw new IllegalArgumentException("invalid age");
} else {
this.age = age; // <------ LINE2 ✓
} // if
} // setAge
On the line labeled LINE1, the code attempts to access
checkAge, an instance method of the current object (i.e., it is
the same as this.checkAge) declared within the same class.
Although that method is private, it is visible from LINE1
because private members are always visible from within the same
class. A similar argument can be made for the code on LINE2,
which attempts to access the private instance variable age.
Test Yourself
Can you directly access something that is declared private within the same class?
9.2.4. Example 2¶
According to The Java Language Specification (JLS) 11 Section 6.6 [ACCESS], the developers of Java incorporated visibility into the language “to prevent the users of a package or class from depending on unnecessary details of the implementation of that package or class.”
To illustrate this idea, let’s consider the UML diagram below and the code snippet that follows it.
public void setAge(int age) {
if (!checkAge(age)) { // <---- LINE1 ✓
throw new IllegalArgumentException("invalid age");
} else {
this.age = age; // <---- LINE2 ✓
} // if
} // setAge
public void updateAges(Person[] persons) {
for (int i = 0; i < persons.length; i++) {
int newAge = persons[i].getAge() + 1;
if (persons[i].checkAge(newAge)) { // <---- LINE1 ✗
persons[i].setAge(newAge);
} // if
} // for
} // updateAges
On the line labeled LINE1, the code attempts to access the
checkAge method, which is an instance method declared within another
class. Since that method is private, it is not visible from this line
because private members are only visible from within the class where
they are declared. If you try to compile OtherClass.java, then
you get the following error:
OtherClass.java: error: checkAge() has private access in Person
The error above is exactly what the author of Person wanted to happen. They
intended for checkAge to only be used by other methods within the Person class.
To make the method not visible from outside the class, they declared it private. Had they
declared it public, for example, then the example would have compiled; however, the call
to checkAge would add unnecessary redundancy since it is called again inside the call
to setAge on the next line (see the previous example for the inside of setAge).
We’re not sure how the author of OtherClass knew about the checkAge method, but
the error message lets them know that it is not for them to use. Had they referred to the
Javadoc/API documentation for the Person class, it is unlikely that the private method
would have been included (private members are not included in the javadoc output by default).
If it is private, then it is not for others, and if it is not even listed in the documentation,
then that’s less stuff that other programmers need to understand before they’re able
to use your code.
Test Yourself
Can you directly access something that is declared private within another class?
9.2.5. Example 3¶
When first studying visibility, it is common for students to think private is more restrictive than it actually is. Consider the UML diagram below and the code snippet for a copy constructor that follows it.
// inside Person.java
public Person(Person other) {
setName(other.name); // <---- LINE1
setAge(other.age); // <------ LINE2
} // setAge
Test Yourself
On the lines labeled LINE1 and LINE2 above, the code attempts to access
the private instance members name and age of the Person object
referred to by other. Will LINE1 compile? How about LINE2?
Test Yourself Solution (open after answering the question above)
It does compile!. Although other.name and other.age
are private, they’re visible from LINE1 and LINE2 because
those lines are in the same class as the declarations.
Remember, private members are always visible from lines in the same class.
The scenario for each line is summarized in the table below.
Member |
Accessed |
|||||
|---|---|---|---|---|---|---|
LINE |
Name |
Declared |
In |
From |
Same Class? |
Visible? |
1 |
|
private |
|
|
Y |
Y |
2 |
|
private |
|
|
Y |
Y |
While a reference to an object does allow us to find members of the object
via .memberName (for some memberName), our ability to access the
member from the current location (line of code) depends only on where the
member is declared and its visibility. In general, visibility itself has
nothing to do with objects; it is all about where the code is written.