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 public modifier 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 -public command-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
  1. Can code outside this class directly modify balance?

    Solution

    Yes. Any code can directly read or modify the balance variable because it is public.

  2. Why might making balance public 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.

  3. How could you redesign this class to allow controlled access to balance while keeping it safe?

    Solution

    Make balance private and provide getter and setter methods that include validation like the code below. This preserves control over how balance is 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 private modifier 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 -private command-line argument (that option will also include anything that is more visible than private — therefore, it will include everything).

Test Yourself

  1. What kinds of declarations can have private visibility in Java?

  2. 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.

hide circle
set namespaceSeparator none
skinparam classAttributeIconSize 0

package cs1302.social {

   class Person {
        -name: String
        -age: int

        +<<new>> Person(name: String, age: int)
        +<<new>> Person(other: Person)
        +getName(): String
        +getAge(): int
        +setName(name: String): void
        +setAge(age: int): void
        -checkAge(age: int): boolean
   }
}

Listing 9.4 Inside Person.java:
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

  1. 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.

hide circle
set namespaceSeparator none
skinparam classAttributeIconSize 0

package cs1302.social {
   OtherClass -up-> Person: uses

   class Person {
        -name: String
        -age: int

        +<<new>> Person(name: String, age: int)
        +<<new>> Person(other: Person)
        +getName(): String
        +getAge(): int
        +setName(name: String): void
        +setAge(age: int): void
        -checkAge(age: int): boolean
   }

   class OtherClass {
        +updateAges(persons: Person[]): void
   }

   hide OtherClass fields
}

Listing 9.5 Inside Person.java:
public void setAge(int age) {
    if (!checkAge(age)) { // <---- LINE1 ✓
        throw new IllegalArgumentException("invalid age");
    } else {
        this.age = age; // <---- LINE2 ✓
    } // if
} // setAge
Listing 9.6 Inside OtherClass.java:
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

  1. 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.

hide circle
set namespaceSeparator none
skinparam classAttributeIconSize 0

package cs1302.social {

   class Person {
        -name: String
        -age: int

        +<<new>> Person(name: String, age: int)
        +<<new>> Person(other: Person)
        +getName(): String
        +getAge(): int
        +setName(name: String): void
        +setAge(age: int): void
        -checkAge(age: int): boolean
   }
}

// 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

name

private

Person

Person

Y

Y

2

age

private

Person

Person

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.