9. Visibility Lesson¶
Visibility¶
Visibility
To see sample solutions, click on the "Configure activity" button and select "Show solutions" from the menu that appears.
Sample solutions not included, because "Show solutions" was not selected before printing.
Learning objectives
After this activity, you should be able to:
Determine whether a class, instance variable, static variable, method, or constructor is accessible from a given location in a program.
Explain how packages and inheritance affect access, including the restrictions on
protectedinstance members outside their package.Distinguish an access violation from a missing method or constructor and from an attempt to instantiate an abstract class.
Correct invalid code without unnecessarily widening access.
Why Visibility?
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."
How to Analyze an Access
Use these questions for each candidate statement:
Which declaration is being accessed? Identify its declaring class and package. For a method call, use the qualifying expression's compile-time type to find the available declaration; the object's runtime class does not make missing methods available to the compiler.
Where does the access occur? Identify the caller's class and package. The caller's location is distinct from the object's class.
Is access permitted? Check the declaring type's accessibility and the declaration's visibility: private, package private, protected, or public. For a protected instance member used outside its declaring package, identify the subclass containing the access and check the qualifying expression's compile-time type.
Is another rule responsible? A missing constructor or method, or an attempt to instantiate an abstract class, is not a visibility violation.
What happens if it compiles? Trace only the stated setup and candidate. Identify copied reference values, shared objects, changes to instance variables, and output. If it does not compile, explain the diagnostic's meaning and propose a correction without unnecessarily widening access.
Judge candidates independently unless the question explicitly asks you to execute statements in sequence. Exact compiler wording is not required. Each scenario specifies its own exit-ticket task and memory-map stopping point.
Part 1: Public and Private Visibility
Introduction
Access control helps a class expose operations that callers can depend on while keeping implementation details internal. It supports encapsulation; it is not a substitute for authorization checks or a security boundary for untrusted code. It helps preserve an author's intentions concerning what other pieces of code can access the entities they declare under normal circumstances.
Read the First UML View
Part 1 uses a simplified Book class whose direct superclass is
Object. Parts 2 and 3 introduce a version that extends Product.
Within each version, a diagram may omit details to focus on the current
question. UML uses + for public, - for
private, ~ for package private, and # for protected. Underlining
identifies static members.
UML Details for Book.java
Bookis a public class incs1302.books.BookDriveris a public class incs1302.books.Book.titleis a privateStringinstance variable.Book(String)is a public constructor.Book(Book)is a public constructor.Book.getTitleis a public instance method.Book.setTitleis a private instance method.BookDriver.mainis a public static method.BookDriverusesBook.
Code for Book.java
1package cs1302.books;
2
3/** A book used to demonstrate private access and reference values. */
4public class Book {
5
6 /** Reference to this book's title string. */
7 private String title;
8
9 /**
10 * Initialize a book with the supplied title reference value.
11 * @param title reference to the title string
12 */
13 public Book(String title) {
14 super();
15 this.setTitle(title);
16 } // Book
17
18 /**
19 * Copy another book's title reference value.
20 * @param other non-null reference to a book object
21 */
22 public Book(Book other) {
23 super();
24 this.title = other.title;
25 } // Book
26
27 /**
28 * Obtain the stored title reference value.
29 * @return the title reference value
30 */
31 public String getTitle() {
32 return this.title; // return with the title reference value
33 } // getTitle
34
35 /**
36 * Replace the stored title reference value.
37 * @param title the new title reference value
38 */
39 private void setTitle(String title) {
40 this.title = title;
41 } // setTitle
42
43} // Book
Scenario 1: Classify Declarations
Here, top-level, member-level, and local-level describe declaration locations for this exercise. Member-level includes constructor declarations in a class body; constructors are not class members in Java's terminology and are not inherited. Local-level includes parameters, which are distinct from local variables declared in a body. See JLS 8.2: Class Members.
On your Exit Ticket:
In Book.java, classify each of the following entity declarations
as top-level, member-level, or local-level:
Book(the class);title(the instance variable);BookandtitleinBook(String);BookandotherinBook(Book);getTitle();setTitleandtitleinsetTitle(String).
On your Exit Ticket: Is this.title = other.title; a declaration?
Sample Solution
Book(the class): top-level (class declaration).title(the instance variable): member-level (instance variable declaration).In
Book(String),Bookis member-level (constructor declaration), andtitleis local-level (parameter variable declaration).In
Book(Book),Bookis member-level (constructor declaration), andotheris local-level (parameter variable declaration).getTitle(): member-level (method declaration).In
setTitle(String),setTitleis member-level (method declaration), andtitleis local-level (parameter variable declaration).
Here, local-level includes parameter declarations; a parameter variable is distinct from a local variable declared in a body. The assignment statement declares nothing: instead, it copies a reference value into the destination instance variable.
Scenario 2: Book Copy Constructor
ACTIVITY: For each potential copy constructor shown below, indicate if it is valid (will compile) or invalid (will not compile) – if it is invalid, then write down why:
1public Book(Book other) {
2 this.setTitle(other.title);
3} // Book
1public Book(Book other) {
2 this.title = other.title;
3} // Book
1public Book(Book other) {
2 super();
3 this.title = other.title;
4} // Book
Solution
Version 1: Will not compile because the
Productconstructor does not take any arguments. When we pass an argument tosuper, the compiler will not be able to find that constructor.Version 2: The first two lines will work as expected. However, the
serialinstance variable inProductcannot be accessed directly from within theBookclass because it is package private.Version 3: This compiles and properly initializes both instance variables in the
Bookobject.
Scenario 3: Accessing Private Entities (1)
This example uses a Book class whose direct superclass is
Object. Each super() invokes the no-argument constructor
of Object.
6Book book0 = new Book("LOTR");
7Book book1 = new Book(book0);
8String title0 = book0.getTitle();
On your Exit Ticket:
Why do you think the author used
setTitle(title)instead ofthis.title = titlein theBook(String)constructor? What might be the benefit?Does the current setter validate its argument? If validation were added later, what would need to be true before the copy constructor could safely bypass it using
this.title = other.title?Draw a memory map immediately after the declaration of
title0finishes, beforemainreturns. Include its three local reference variables, both book objects, and the shared title string.
Sample Solution
Centralize an assignment: The current
setTitlemethod only assigns the supplied reference value. It acceptsnull, empty strings, and strings containing only whitespace. Using it gives the class one place where validation could be added later; private visibility does not itself validate data.Copy a reference value: The copy constructor can access
other.titlebecause the access occurs insideBook. It copies the stored reference value without copying the string. Bypassing a future validation check is justified only if the class maintains an invariant that every existing book has a valid title. Every construction and update path would need to preserve that invariant. The current implementation provides no such guarantee. The copy constructor separately requires a non-nullother.Distinguish the objects:
book0andbook1refer to two distinct book objects. Theirtitleinstance variables andtitle0refer to the same"LOTR"string object.
Scenario 4: Accessing Private Entities (2)
This example uses a Book class whose direct superclass is
Object. Each super() invokes the no-argument constructor
of Object.
6Book book0 = new Book("LOTR");
7Book book1 = new Book(book0);
8book1.setTitle("The Lord of the Rings");
On your Exit Ticket: There is an issue with the code in the main method.
Is it a run-time issue or compile-time issue? Identify the declaration
being accessed, its visibility, and the caller's location. Explain the
meaning of the compiler diagnostic; exact wording is not required.
Sample Solution
6Book book0 = new Book("LOTR");
7Book book1 = new Book(book0);
8book1.setTitle("The Lord of the Rings");
Compiler error (expected)
cs1302/books/BookDriver.java:8: error: setTitle(String) has private access in Book
book1.setTitle("The Lord of the Rings");
^
1 error
Scenario 5: More Access from BookDriver
On your Exit Ticket: Judge these candidate statements independently, note your group's thoughts, and how to address any issues (if you think there are any):
1Book book = new Book("1984");
2
3System.out.println(book.getTitle()); // A
4book.setTitle("Dune"); // B
5System.out.println(book.title); // C
Sample Solution A
A compiles: getTitle is public in the public class Book.
The call reads the stored title reference value, and the print
statement outputs 1984.
6Book book = new Book("1984");
7System.out.println(book.getTitle()); // A
Example of main method in BookDriver.java [code listing] [download] [open]¶
Sample Solution B
B does not compile: setTitle is private to Book. Sharing a
package does not grant private access. Supply the desired title when
constructing a book:
book = new Book("Dune");. This replaces the reference value
in book; it does not rename the previous object.
6Book book = new Book("1984");
7book.setTitle("Dune"); // B
Compiler error (expected)
cs1302/books/BookDriver.java:7: error: setTitle(String) has private access in Book
book.setTitle("Dune"); // B
^
1 error
Sample Solution C
C does not compile: title is a private instance variable of
Book. Use book.getTitle() as in A.
6Book book = new Book("1984");
7System.out.println(book.title); // C
Compiler error (expected)
cs1302/books/BookDriver.java:7: error: title has private access in Book
System.out.println(book.title); // C
^
1 error
Part 2: Package Private and Accessible Classes
Introduction
From this part onward, use the extended Book class in
cs1302-visibility: it extends Product and adds serial-number
behavior. This replaces Part 1's simplified class; do not combine both
versions in the same package. Part 3 examines the inheritance rules.
A top-level class can be public or package private (no access
modifier). It cannot be declared private or protected. A public member
does not make its enclosing top-level class accessible from another
package. For these class members and constructors, omitting an access
modifier makes the declaration package private, but only in the Java
source code. Use ~ to denote package private declarations in UML
diagrams.
Reveal the Second Package
UML Details for the Two Packages
Productis a public abstract class incs1302.inventory.BookextendsProductfromcs1302.books.InventoryManagerusesProduct.InventoryManageris a public class incs1302.inventory.InventoryDriveris a public class incs1302.inventory.Utilityis a package private class incs1302.inventory.InventoryManager.inventoryis a privateProduct[]instance variable.InventoryManager()is a private constructor.InventoryManager.getManageris a public static method.InventoryManager.addItemis a package private instance method.InventoryManager.requestPurchaseis a public instance method.InventoryManager.nullCheckis a private static method.Utility()is a private constructor.Utility.minis a public static method.BookDriverusesInventoryManager.InventoryDriverusesInventoryManager.InventoryDriverusesBook.
Book.java: Extended Version
1package cs1302.books;
2
3import cs1302.inventory.Product;
4
5/** A product with a title. */
6public class Book extends Product {
7
8 /** Reference to this book's title string. */
9 private String title;
10
11 /**
12 * Initialize a book with the supplied title reference value.
13 * @param title reference to the title string
14 */
15 public Book(String title) {
16 super();
17 this.setTitle(title);
18 } // Book
19
20 /**
21 * Copy another book's title reference value and serial number.
22 * @param other non-null reference to a book object
23 */
24 public Book(Book other) {
25 super();
26 this.title = other.title;
27 this.setSerial(other.getSerial());
28 } // Book
29
30 /**
31 * Obtain the stored title reference value.
32 * @return the title reference value
33 */
34 public String getTitle() {
35 return this.title; // return with the title reference value
36 } // getTitle
37
38 /**
39 * Replace the stored title reference value.
40 * @param title the new title reference value
41 */
42 private void setTitle(String title) {
43 this.title = title;
44 } // setTitle
45
46 /**
47 * Demonstrate permitted protected access from this subclass.
48 * @param other non-null reference to a book object
49 */
50 public void updateSerials(Book other) {
51 this.setSerial(10);
52 other.setSerial(20); // the qualifying expression has type Book
53 } // updateSerials
54
55} // Book
InventoryManager.java
1package cs1302.inventory;
2
3/** Small manager used to demonstrate package and private access. */
4public class InventoryManager {
5
6 /** Reference to this manager's array of product references. */
7 private Product[] inventory;
8
9 /** Prevent callers outside this class from invoking this constructor. */
10 private InventoryManager() {
11 this.inventory = new Product[0]; // Start with an empty array object.
12 } // InventoryManager
13
14 /**
15 * Create a manager object.
16 * @return a reference to a new manager object
17 */
18 public static InventoryManager getManager() {
19 return new InventoryManager(); // return with the new reference value
20 } // getManager
21
22 /**
23 * Assign a serial number from within the declaring package.
24 * This teaching example leaves the inventory array empty.
25 * @param product non-null reference to a product object
26 */
27 void addItem(Product product) {
28 InventoryManager.nullCheck(product);
29 product.serial = 14; // serial is package private
30 product.setSerial(15); // setSerial is protected; this caller shares its package
31 } // addItem
32
33 /**
34 * Check a product supplied by a caller.
35 * @param product non-null reference to a product object
36 */
37 public void requestPurchase(Product product) {
38 InventoryManager.nullCheck(product);
39 } // requestPurchase
40
41 /**
42 * Reject a null argument value.
43 * @param object reference value to check
44 * @throws IllegalArgumentException if the value is null
45 */
46 private static void nullCheck(Object object) {
47 if (object == null) {
48 throw new IllegalArgumentException("A product reference is required.");
49 } // if
50 } // nullCheck
51
52} // InventoryManager
Utility.java
1package cs1302.inventory;
2
3/** Package private class with a public static helper method. */
4class Utility {
5
6 /** Prevent construction outside this class. */
7 private Utility() {
8 } // Utility
9
10 /**
11 * Select the smaller of two values.
12 * @param first the first value
13 * @param second the second value
14 * @return the smaller value
15 */
16 public static long min(long first, long second) {
17 return Math.min(first, second); // return with the smaller value
18 } // min
19
20} // Utility
This manager demonstrates access rules, not a complete inventory
system. Each manager's private inventory instance variable stores
a reference to a distinct Product[] array object of length 0.
Creating this empty array does not create any product objects.
Include the array and its reference from the manager in memory maps.
addItem assigns a serial number without storing products; neither
it nor requestPurchase changes the inventory array.
getManager returns with a reference to a new manager object on
each call. Its call to the private constructor is permitted because
it occurs inside InventoryManager.
Visibility Practice: Change the Caller's Package
Scenario 1: Calls from BookDriver
Import InventoryManager from cs1302.inventory in BookDriver.java.
Inside BookDriver.main, use this setup.
1Book book = new Book("1984");
2InventoryManager manager = InventoryManager.getManager();
On your Exit Ticket: Judge each candidate independently.
Predict any compile-time error; for valid code, draw the memory map
just before main completes. Explain the visibility rule and
suggest a correction for each invalid candidate.
1manager.addItem(book); // A
2manager.requestPurchase(book); // B
3InventoryManager.nullCheck(book); // C
4manager = new InventoryManager(); // D
5System.out.println(Utility.min(3, 8)); // E
For candidate E only, add this import above the class declaration:
1import cs1302.inventory.Utility;
Sample Solution A
A does not compile: addItem is package private in cs1302.inventory.
Place this operation inside an appropriate inventory-package method.
1package cs1302.books;
2
3import cs1302.inventory.InventoryManager;
4
5/** Demonstrate one access from outside the inventory package. */
6public class BookDriver {
7
8 /**
9 * Run this independent visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 manager.addItem(book);
17 } // main
18
19} // BookDriver
Compiler error (expected)
cs1302/books/BookDriver.java:16: error: addItem(Product) is not public in InventoryManager; cannot be accessed from outside package
manager.addItem(book);
^
1 error
Sample Solution B
B compiles: requestPurchase is public in the public class InventoryManager.
It checks the supplied reference value without changing the book object.
1package cs1302.books;
2
3import cs1302.inventory.InventoryManager;
4
5/** Demonstrate one access from outside the inventory package. */
6public class BookDriver {
7
8 /**
9 * Run this independent visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 manager.requestPurchase(book);
17 } // main
18
19} // BookDriver
Final captured memory state. [code listing] [download] [open]¶
Sample Solution C
C does not compile: nullCheck is private to InventoryManager.
Use its public requestPurchase method, which performs the check internally.
1package cs1302.books;
2
3import cs1302.inventory.InventoryManager;
4
5/** Demonstrate one access from outside the inventory package. */
6public class BookDriver {
7
8 /**
9 * Run this independent visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 InventoryManager.nullCheck(book);
17 } // main
18
19} // BookDriver
Compiler error (expected)
cs1302/books/BookDriver.java:16: error: nullCheck(Object) has private access in InventoryManager
InventoryManager.nullCheck(book);
^
1 error
Sample Solution D
D does not compile: the constructor is private to InventoryManager.
Call InventoryManager.getManager() instead; it returns with a reference
to a new manager object.
1package cs1302.books;
2
3import cs1302.inventory.InventoryManager;
4
5/** Demonstrate one access from outside the inventory package. */
6public class BookDriver {
7
8 /**
9 * Run this independent visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 manager = new InventoryManager();
17 } // main
18
19} // BookDriver
Compiler error (expected)
cs1302/books/BookDriver.java:16: error: InventoryManager() has private access in InventoryManager
manager = new InventoryManager();
^
1 error
Sample Solution E
E does not compile: Utility is a package private class in another package.
Both the import and the use of Utility produce compile-time errors.
Its public min method does not make the class accessible.
Use Math.min(3, 8) instead.
1package cs1302.books;
2
3import cs1302.inventory.InventoryManager;
4import cs1302.inventory.Utility;
5
6/** Demonstrate one access from outside the inventory package. */
7public class BookDriver {
8
9 /**
10 * Run this independent visibility candidate.
11 * @param args unused command-line arguments
12 */
13 public static void main(String[] args) {
14 Book book = new Book("1984");
15 InventoryManager manager = InventoryManager.getManager();
16 // the next line is different for each candidate
17 System.out.println(Utility.min(3, 8));
18 } // main
19
20} // BookDriver
Compiler error (expected)
cs1302/books/BookDriver.java:4: error: Utility is not public in cs1302.inventory; cannot be accessed from outside package
import cs1302.inventory.Utility;
^
cs1302/books/BookDriver.java:17: error: Utility is not public in cs1302.inventory; cannot be accessed from outside package
System.out.println(Utility.min(3, 8));
^
2 errors
Scenario 2: Calls from InventoryDriver
Import Book from cs1302.books in InventoryDriver.java.
Inside InventoryDriver.main, use this setup.
1Book book = new Book("1984");
2InventoryManager manager = InventoryManager.getManager();
On your Exit Ticket: Judge each candidate independently.
Predict any compile-time error; for valid code, draw the memory map
just before main completes. Explain the visibility rule and
suggest a correction for each invalid candidate.
1manager.addItem(book); // A
2manager.requestPurchase(book); // B
3InventoryManager.nullCheck(book); // C
4manager = new InventoryManager(); // D
5System.out.println(Utility.min(3, 8)); // E
Sample Solution A
A compiles because addItem is package private and the caller shares its package.
The method changes the book object's serial number to 14 and then 15.
Sample Solution B
B compiles: requestPurchase is public in the public class InventoryManager.
It checks the supplied reference value without changing the book object.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 manager.requestPurchase(book);
17 } // main
18
19} // InventoryDriver
Final captured memory state. [code listing] [download] [open]¶
Sample Solution C
C does not compile: nullCheck is private to InventoryManager.
Use its public requestPurchase method, which performs the check internally.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 InventoryManager.nullCheck(book);
17 } // main
18
19} // InventoryDriver
Compiler error (expected)
cs1302/inventory/InventoryDriver.java:16: error: nullCheck(Object) has private access in InventoryManager
InventoryManager.nullCheck(book);
^
1 error
Sample Solution D
D does not compile: the constructor is private to InventoryManager.
Call InventoryManager.getManager() instead; it returns with a reference
to a new manager object.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 manager = new InventoryManager();
17 } // main
18
19} // InventoryDriver
Compiler error (expected)
cs1302/inventory/InventoryDriver.java:16: error: InventoryManager() has private access in InventoryManager
manager = new InventoryManager();
^
1 error
Sample Solution E
E compiles: Utility is accessible in its own package, and min is public.
The method returns with the long value 3, which is printed.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 InventoryManager manager = InventoryManager.getManager();
15 // the next line is different for each candidate
16 System.out.println(Utility.min(3, 8));
17 } // main
18
19} // InventoryDriver
Final captured memory state. [code listing] [download] [open]¶
Sharing a package does not grant private access. Package names are exact: a subpackage does not gain access to declarations in its parent package.
Part 3: Protected Access and Other Compilation Rules
Reveal the Superclass
UML Details for the Inheritance View
Productis a public abstract class incs1302.inventory.Product.serialis a package privatelonginstance variable.Product()is a public no-argument constructor.Product.getSerialis a public instance method.Product.setSerialis a protected instance method.BookextendsProductfromcs1302.books.InventoryManagerusesProduct.
Product.java
1package cs1302.inventory;
2
3/** Base class for products used in the visibility lesson. */
4public abstract class Product {
5
6 /** Serial number; accessible within this package. */
7 long serial;
8
9 /** Initialize the serial number to zero. */
10 public Product() {
11 this.serial = 0;
12 } // Product
13
14 /**
15 * Obtain the serial number.
16 * @return the serial number
17 */
18 public long getSerial() {
19 return this.serial; // return with the serial number
20 } // getSerial
21
22 /**
23 * Change the serial number.
24 * @param serial the new serial number
25 */
26 protected void setSerial(long serial) {
27 this.serial = serial;
28 } // setSerial
29
30} // Product
Protected Access Across Packages
Within cs1302.inventory, setSerial is accessible without requiring
a subclass. Outside that package, access to this protected instance
method must occur within a subclass body. When the access uses a
qualifying expression, that expression's compile-time type must be
that subclass or one of its subclasses.
For example, inside Book, other.setSerial(20) is permitted when
other has type Book. A variable of type Product does not meet
that condition, even when its value refers to a Book object.
See JLS 6.6.2.1: protected members.
Visibility Reference Table
Access level |
Declaring class |
Other class in same package |
Different package |
|---|---|---|---|
|
Yes |
Yes |
Yes, if the class is accessible |
|
Yes |
Yes |
Subclass access, with the restriction described in Protected Access Across Packages |
package private |
Yes |
Yes |
No |
|
Yes, including through another instance |
No |
No |
This guide assumes the lesson's top-level classes. Nested classes and
protected constructors require additional rules; the Product
constructor here is public.
Visibility Practice: Classify the Failure
Scenario 1: Constructor Alternatives
1Book original = new Book("1984");
2original.updateSerials(original); // the serial number becomes 20
3Book copy = new Book(original);
On your Exit Ticket: Consider each alternative declaration of
Book(Book other) independently. Predict whether it compiles,
identify the governing rule, and correct any invalid alternative.
For the valid alternative, draw the memory map after the declaration
of copy finishes, before main returns. Include both local
reference variables, both book objects, and their title references
and serial numbers.
Alternative A
1/**
2 * Copy another book's title reference value and serial number.
3 * @param other non-null reference to a book object
4 */
5public Book(Book other) {
6 super(42L);
7 this.title = other.title;
8} // Book
Alternative B
1/**
2 * Copy another book's title reference value and serial number.
3 * @param other non-null reference to a book object
4 */
5public Book(Book other) {
6 super();
7 this.title = other.title;
8 this.serial = other.getSerial();
9} // Book
Alternative C
1/**
2 * Copy another book's title reference value and serial number.
3 * @param other non-null reference to a book object
4 */
5public Book(Book other) {
6 super();
7 this.title = other.title;
8 this.setSerial(other.getSerial());
9} // Book
Sample Solution A
A does not compile: Product has no constructor accepting a long
argument. Use super(); this failure is not a visibility violation.
6Book original = new Book("1984");
7original.updateSerials(original); // the serial number becomes 20
8Book copy = new Book(original);
Compiler error (expected)
cs1302/books/Book.java:25: error: constructor Product in class Product cannot be applied to given types;
super(42L);
^
required: no arguments
found: long
reason: actual and formal argument lists differ in length
1 error
Sample Solution B
B does not compile: serial is package private in cs1302.inventory.
Use the inherited protected setSerial method as in C.
6Book original = new Book("1984");
7original.updateSerials(original); // the serial number becomes 20
8Book copy = new Book(original);
Compiler error (expected)
cs1302/books/Book.java:27: error: serial is not public in Product; cannot be accessed from outside package
this.serial = other.getSerial();
^
1 error
Sample Solution C
C compiles. super() invokes the public no-argument constructor.
Private access to other.title occurs inside Book, and
this.setSerial is permitted subclass access. The new book has its own
instance variables, with a copy of the title reference value and serial number.
Scenario 2: Compile-Time Type versus Object Class
Import Book from cs1302.books in InventoryDriver.java.
Inside InventoryDriver.main, use this setup:
1Book book = new Book("1984");
2Product product = book; // copies the reference value; both refer to one object
On your Exit Ticket: Judge each candidate independently.
Predict compile-time errors and explain their causes. For each valid
candidate, draw the memory map just before main completes.
1System.out.println(product.getTitle()); // A
2product.setSerial(14); // B
3product.serial = 14; // C
4Product another = new Product(); // D
Sample Solution A
A does not compile: the compile-time type Product does not declare
or inherit getTitle. This is not a visibility violation.
Use book.getTitle() instead.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 Product product = book; // copies the reference value; both refer to one object
15
16 System.out.println(product.getTitle());
17 } // main
18
19} // InventoryDriver
Compiler error (expected)
cs1302/inventory/InventoryDriver.java:16: error: cannot find symbol
System.out.println(product.getTitle());
^
symbol: method getTitle()
location: variable product of type Product
1 error
Sample Solution B
B compiles: setSerial is protected, and the caller shares its
declaring package. Both reference variables still refer to the same
book object, whose serial number is now 14.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 Product product = book; // copies the reference value; both refer to one object
15
16 product.setSerial(14);
17 } // main
18
19} // InventoryDriver
cs1302/inventory/InventoryDriver.java [code listing] [download] [open]¶
Sample Solution C
C compiles: serial is package private, and the caller is in
cs1302.inventory. The assignment changes the same book object
observed through both reference variables.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 Product product = book; // copies the reference value; both refer to one object
15
16 product.serial = 14;
17 } // main
18
19} // InventoryDriver
cs1302/inventory/InventoryDriver.java [code listing] [download] [open]¶
Sample Solution D
D does not compile because Product is abstract, even though its
constructor is public. Use Product another = new Book("Dune");.
Constructing a book invokes a superclass constructor to initialize state
in that same object; it does not construct a separate Product object.
1package cs1302.inventory;
2
3import cs1302.books.Book;
4
5/** Demonstrate one independent inventory-package access. */
6public class InventoryDriver {
7
8 /**
9 * Run this visibility candidate.
10 * @param args unused command-line arguments
11 */
12 public static void main(String[] args) {
13 Book book = new Book("1984");
14 Product product = book; // copies the reference value; both refer to one object
15
16 Product another = new Product();
17 } // main
18
19} // InventoryDriver
Compiler error (expected)
cs1302/inventory/InventoryDriver.java:16: error: Product is abstract; cannot be instantiated
Product another = new Product();
^
1 error
Scenario 3: Protected Access through a Parameter
1Book first = new Book("1984");
2Book second = new Book("Dune");
3first.updateSerials(second);
On your Exit Ticket: Compare these alternatives inside Book.
Each replaces updateSerials independently and uses the caller
setup above, which creates two distinct book objects. Does each
method compile? Does the referred-to object's class change the
access rule? For the valid alternative, draw the memory map just
before updateSerials returns. Include first and second
in main, the parameter other, and the object referred to by
this in the active method call.
Alternative A
1public void updateSerials(Book other) {
2 this.setSerial(10);
3 other.setSerial(20);
4} // updateSerials
Alternative B
1public void updateSerials(Product other) {
2 this.setSerial(10);
3 other.setSerial(20);
4} // updateSerials
Sample Solution A
A compiles: access occurs inside the subclass Book, and the
qualifying expression other has compile-time type Book.
The first book's serial number becomes 10 and the second's becomes 20.
Java passes arguments by value: the reference value is copied into
parameter variable other; no book object is copied.
Sample Solution B
B does not compile: other has compile-time type Product.
Outside Product's package, this access inside Book requires a
qualifying expression whose type is Book or a subclass of Book.
The class of the referred-to object does not change that rule.
Use the Book parameter type as in A when that matches the operation's contract.
The access through this remains permitted in both alternatives.
6Book first = new Book("1984");
7Book second = new Book("Dune");
8first.updateSerials(second);
Compiler error (expected)
cs1302/books/Book.java:52: error: setSerial(long) has protected access in Product
other.setSerial(20); // the qualifying expression has type Product
^
1 error
Additional Practice: Apply the Visibility Rules
Scenario 1: Two Objects, One Declaring Class
Inside Book(Book other), immediately after super(), consider
these statements in order. The original book's title is "1984".
1this.title = other.title; // A
2other.setTitle("Dune"); // B
On your Exit Ticket: Does each statement compile inside Book?
Explain which object's instance variable each statement changes.
Draw a memory map immediately after statement B executes inside the
copy constructor. Include its parameter other and the object
referred to by this. Would a driver
be permitted to perform the same accesses through book references?
Explain the rule and suggest corrections without changing visibility.
Sample Solution A and B: Inside Book
Both statements compile because the accesses occur inside Book.
A copies the title reference value into the new object's instance variable.
B changes the original object's title reference value; it does not modify
a String object. The new book retains the reference to "1984"
while the original book now refers to "Dune" through its title variable.
Sample Solution A: Access from BookDriver
This driver cannot access either private title variable.
Use the public copy constructor to create a book with the same title.
The driver uses copy instead of this because static main
has no current object.
6Book original = new Book("1984");
7Book copy = new Book(original);
8copy.title = original.title;
Compiler error (expected)
cs1302/books/BookDriver.java:8: error: title has private access in Book
copy.title = original.title;
^
cs1302/books/BookDriver.java:8: error: title has private access in Book
copy.title = original.title;
^
2 errors
Sample Solution B: Access from BookDriver
setTitle is private to Book and cannot be called here.
The driver can read the title using getTitle or construct a new book
with the desired title. The class has no public operation for changing
an existing book's title.
6Book original = new Book("1984");
7Book copy = new Book(original);
8original.setTitle("Dune");
Compiler error (expected)
cs1302/books/BookDriver.java:8: error: setTitle(String) has private access in Book
original.setTitle("Dune");
^
1 error
Scenario 2: Protected Access through Two Reference Variables
Suppose this method is added inside Book:
1public void revise(Book book, Product product) {
2 this.setSerial(1); // A
3 book.setSerial(2); // B
4 product.setSerial(3); // C
5 book.serial = 4; // D
6} // revise
On your Exit Ticket: Judge each labeled statement independently,
with the other three omitted. Predict whether it compiles and explain
the access rule. Correct invalid statements without changing visibility.
For valid statements, draw a memory map just before revise returns
to its caller. Include the caller's variables, both parameter variables,
and the object referred to by this:
1Book first = new Book("1984");
2Book second = new Book("Dune");
3first.revise(second, second);
The call supplies one argument for each parameter. Each argument evaluates to a reference value that is copied into its parameter variable; Java passes by value and does not copy either book object.
Sample Solution A
A compiles: access occurs inside subclass Book, and this
has type Book. The first book's serial number becomes 1;
the second book's serial number remains 0.
Sample Solution B
B compiles: the qualifying expression book has type Book.
The second book's serial number becomes 2; the first remains 0.
Both parameter variables refer to the second book object.
Sample Solution C
C does not compile: product has compile-time type Product.
For this access inside Book outside the declaring package, its type
must be Book or a subclass of Book. Referring to a book object
does not change that rule. If the operation is intended for books,
change the parameter's declared type to Book.
6Book first = new Book("1984");
7Book second = new Book("Dune");
8first.revise(second, second);
Compiler error (expected)
cs1302/books/Book.java:60: error: setSerial(long) has protected access in Product
product.setSerial(3);
^
1 error
Sample Solution D
D does not compile: serial is package private in another package.
Replace the statement with book.setSerial(4) to use permitted
protected access inside Book. A driver in the book package cannot
make that protected call merely because it shares a package with Book.
6Book first = new Book("1984");
7Book second = new Book("Dune");
8first.revise(second, second);
Compiler error (expected)
cs1302/books/Book.java:60: error: serial is not public in Product; cannot be accessed from outside package
book.serial = 4;
^
1 error