Topic: Class inheritance and subclass design
Skills Tested: Creating subclasses, super keyword, constructor chaining, method overriding, equals() comparison
Curriculum Alignment: Unit 5 (Writing Classes), Unit 9 (Inheritance)
Question
The Book class is used to store information about a book. A partial Book class definition is shown.
Provided Book Class
public class Book {
/** The title of the book */
private String title;
/** The price of the book */
private double price;
/** Creates a new Book with given title and price */
public Book(String bookTitle, double bookPrice) {
/* implementation not shown */
}
/** Returns the title of the book */
public String getTitle() {
return title;
}
/** Returns a string containing the title and price of the Book */
public String getBookInfo() {
return title + "-" + price;
}
// There may be instance variables, constructors, and methods
// that are not shown.
}
Your Task
Write a class Textbook, which is a subclass of Book.
A Textbook has an edition number, which is a positive integer used to identify different versions of the book.
The getBookInfo method, when called on a Textbook, returns a string that also includes the edition information.
Requirements
- Information about the book title and price must be maintained in the Book class.
- Information about the edition must be maintained in the Textbook class.
- The Textbook class must have a
canSubstituteFormethod that returnstrueif a Textbook is a valid substitute for another Textbook. - A Textbook is a valid substitute if:
- The two Textbook objects have the same title, AND
- The edition of the current Textbook is greater than or equal to the edition of the parameter.
Examples
| Statement | Value Returned | Explanation |
|---|---|---|
Textbook bio2015 = new Textbook("Biology", 49.75, 2); |
(object created) | bio2015 has title "Biology", price 49.75, edition 2 |
Textbook bio2019 = new Textbook("Biology", 39.75, 3); |
(object created) | bio2019 has title "Biology", price 39.75, edition 3 |
bio2019.getEdition(); |
3 |
The edition is returned |
bio2019.getBookInfo(); |
"Biology-39.75-3" |
Formatted string with title, price, and edition |
bio2019.canSubstituteFor(bio2015); |
true |
Same title, and edition 3 ≥ edition 2 |
bio2015.canSubstituteFor(bio2019); |
false |
Same title, but edition 2 < edition 3 |
Textbook math = new Textbook("Calculus", 45.25, 1); |
(object created) | math has title "Calculus", price 45.25, edition 1 |
bio2015.canSubstituteFor(math); |
false |
Different titles ("Biology" ≠ "Calculus") |
Solution & Explanation
Complete Textbook Class
public class Textbook extends Book {
private int edition;
// Constructor
public Textbook(String title, double price, int ed) {
super(title, price);
edition = ed;
}
// Accessor for edition
public int getEdition() {
return edition;
}
// Override getBookInfo to include edition
@Override
public String getBookInfo() {
return super.getBookInfo() + "-" + edition;
}
// Check if this textbook can substitute for another
public boolean canSubstituteFor(Textbook other) {
return this.getTitle().equals(other.getTitle())
&& this.edition >= other.edition;
}
}
Step-by-Step Explanation
1. Class Declaration
public class Textbook extends Book
- Uses
extendskeyword to create inheritance relationship - Textbook IS-A Book (can do everything a Book can do, plus more)
- Inherits all public/protected methods and fields from Book
2. Private Instance Variable
private int edition;
- Stores the edition number for this textbook
- Must be
private(encapsulation best practice) - Maintained in Textbook class, not Book class (as required)
3. Constructor with super()
public Textbook(String title, double price, int ed) {
super(title, price);
edition = ed;
}
- Takes 3 parameters:
title,price,ed super(title, price)MUST be first line- Calls Book's constructor to initialize inherited fields (title, price)
- Cannot access
titleandpricedirectly (they're private in Book) - Then initializes the
editionfield
super() call MUST be the first statement in the constructor. Without it, the Book fields won't be properly initialized.
4. getEdition() Accessor Method
public int getEdition() {
return edition;
}
- Standard accessor (getter) method
- Returns the edition number
- Required because
editionis private
5. Override getBookInfo()
@Override
public String getBookInfo() {
return super.getBookInfo() + "-" + edition;
}
-
@Overrideannotation indicates this method overrides a parent method -
super.getBookInfo()calls Book's version to get"title-price" - Concatenates
"-" + editionto add edition number - Returns format:
"title-price-edition" -
Must use
super.getBookInfo()because we can't access private fields directly
6. canSubstituteFor() Method
public boolean canSubstituteFor(Textbook other) {
return this.getTitle().equals(other.getTitle())
&& this.edition >= other.edition;
}
- Takes another Textbook as parameter
- Compares titles using
equals()method (NOT ==) - Uses
getTitle()becausetitleis private in Book - Compares edition numbers using
>=operator - Both conditions must be true (uses
&&) - Returns
trueonly if same title AND this edition ≥ other edition
== instead of equals() for String comparison. The == operator checks if two variables reference the same object, not if they have the same content.
Detailed Explanation
Key Concepts Tested
1. Inheritance Fundamentals
This FRQ tests your understanding of the IS-A relationship. A Textbook IS-A Book with additional features. This means:
- Textbook inherits all public methods from Book
- Textbook can call Book's methods using
super - Textbook can override Book's methods to customize behavior
- Textbook cannot directly access Book's private fields
2. The super Keyword
The super keyword has two important uses in this problem:
-
super(params)- Calls the parent class constructor -
super.method()- Calls the parent class method
You cannot use super.field because fields are typically private in the parent class.
3. Method Overriding
When you override getBookInfo() in Textbook:
- The method signature must match exactly
- You can use
@Overrideannotation (recommended) - You can call the parent version with
super.getBookInfo() - This is called extending the parent method's behavior
4. String Comparison with equals()
For the canSubstituteFor method, you must use equals() to compare Strings:
// ✅ CORRECT
this.getTitle().equals(other.getTitle())
// ❌ WRONG - compares memory addresses, not content
this.getTitle() == other.getTitle()
Why This Design?
The problem is designed to test whether you understand the proper relationship between classes:
- Book maintains general book information (title, price)
- Textbook adds specific information (edition)
- Title and price belong in Book because all books have these
- Edition belongs in Textbook because only textbooks have editions
Constructor Chaining
The constructor demonstrates constructor chaining:
public Textbook(String title, double price, int ed) {
super(title, price); // Chain to Book constructor
edition = ed; // Initialize Textbook-specific field
}
This ensures that Book's fields are properly initialized before Textbook adds its own initialization.
Common Mistakes to Avoid
Constructor Errors
- ❌ Not calling super(): Forgetting
super(title, price)in constructor - ❌ Wrong super() placement: Calling
super()after initializing edition (must be first) - ❌ Wrong parameters: Calling
super(title, price, ed)(Book constructor only takes 2 parameters)
Field Access Errors
- ❌ Direct field access: Trying to use
this.titleorthis.price(they're private in Book) - ❌ Using super.title: Trying
super.title(still can't access private fields) - ✅ Correct approach: Use
getTitle()method orsuper.getBookInfo()
Method Override Errors
- ❌ Not using super: Rewriting all the Book logic instead of calling
super.getBookInfo() - ❌ Wrong return format: Returning
"title-edition"instead of"title-price-edition" - ❌ Wrong method signature: Changing parameters or return type (breaks override)
canSubstituteFor Errors
- ❌ Using == for Strings:
this.getTitle() == other.getTitle()(checks references, not content) - ❌ Wrong comparison operator: Using
>instead of>=for edition - ❌ Wrong boolean logic: Using
||instead of&& - ❌ Direct field access: Using
other.titleinstead ofother.getTitle()
Declaration Errors
- ❌ Wrong visibility: Making edition
publicinstead ofprivate - ❌ Missing accessor: Not providing
getEdition()method - ❌ Wrong class declaration: Not using
extends Book
super() correctly in constructor, (2) Calling super.getBookInfo() in override, (3) Using equals() for String comparison. Time yourself for 20 minutes.
Scoring Rubric
Total: 9 Points
| Point | Criteria |
|---|---|
| 1 | Class header declares Textbook extends Book |
| 1 | Declares private int edition instance variable |
| 1 | Constructor header with correct parameters (String, double, int) |
| 1 | Calls super(title, price) to initialize Book fields |
| 1 | Initializes edition field in constructor |
| 1 | getEdition() method returns edition |
| 1 | getBookInfo() calls super.getBookInfo() and includes edition |
| 1 | canSubstituteFor() compares titles using equals() |
| 1 | canSubstituteFor() correctly compares editions with >= and returns boolean |
Penalty Deductions (Max 3)
- -1: Array/collection access confusion
- -1: Extraneous code that causes side effects
- -1: Local variables used but not declared
- -1: Destruction of persistent data
- -1: Void method returns a value
📄 Official College Board Resources
Written by Tanner, Certified AP Computer Science Teacher with 5+ years teaching AP CSA.
Last updated: