CompSci.rocks
FRQcsapa

Book / Textbook: 2022 FRQ 2

A step-by-step solution to the 2022 AP CSA FRQ 2 (Textbook), covering inheritance, super() constructors, and method overriding in Java.

Writing a subclass that extends a given parent class is at the heart of this AP Computer Science A free-response question — you add a new field and new behavior on top of what the parent class already provides, without ever touching its private data directly.

What This FRQ Tests

  • AP CSA units: Unit 9 (Inheritance) and Unit 5 (Writing Classes)
  • Core skill: extending a class with extends, calling the parent's constructor with super(...), and overriding a method so it extends rather than replaces the parent behavior
  • Secondary skill: respecting private access — a subclass cannot read or write a parent's private fields directly, even though it inherits them
  • Official category: "Classes" — always FRQ 2 on the AP CSA exam

The Setup

  • The given Book class has:
    • private String title and private double price — both inaccessible directly from any subclass
    • A constructor: Book(String bookTitle, double bookPrice)
    • String getTitle() — a public getter for the title
    • String getBookInfo() — returns "title-price" as a formatted String
  • You're asked to write a new class, Textbook, that:
    • Extends Book
    • Adds one new field: a positive int edition number
    • Overrides getBookInfo() so it also includes the edition, formatted as "title-price-edition"
    • Adds a new method: canSubstituteFor(Textbook other)
  • The substitution rule: the current Textbook can substitute for other if both are true:
    1. The two Textbook objects have the same title
    2. The current object's edition is greater than or equal to other's edition

Building the Textbook Class

Step-by-Step Approach

  1. Declare the class as public class Textbook extends Book — this is what makes it a subclass.
  2. Add exactly one new instance field: private int edition. (title and price already exist — they live in Book, and Textbook inherits access to them through public methods, not directly.)
  3. Write a constructor that takes all three pieces of data (title, price, edition), forwards title and price to Book's constructor with super(...), and sets edition itself.
  4. Add a simple getter, getEdition(), since nothing else exposes the edition yet.
  5. Override getBookInfo(): call the parent version with super.getBookInfo() to get "title-price", then append "-" + edition.
  6. Write canSubstituteFor(Textbook other): compare titles with .equals(), compare editions with >=, and combine both with &&.

The Code

public class Textbook extends Book
{
    private int edition;

    public Textbook(String bookTitle, double bookPrice, int bookEdition)
    {
        super(bookTitle, bookPrice);
        edition = bookEdition;
    }

    public int getEdition()
    {
        return edition;
    }

    public String getBookInfo()
    {
        return super.getBookInfo() + "-" + edition;
    }

    public boolean canSubstituteFor(Textbook other)
    {
        return getTitle().equals(other.getTitle()) && edition >= other.getEdition();
    }
}

Why Each Piece Matters

  • super(bookTitle, bookPrice) — this is the only way to initialize title and price. They're private in Book, so Textbook cannot assign them directly (title = bookTitle; inside Textbook would not even compile).
  • super.getBookInfo() — reuses Book's existing formatting logic instead of retyping title + "-" + price. If Book ever changed its formatting, Textbook would automatically follow along.
  • getTitle().equals(other.getTitle()) — always compare String contents with .equals(), never ==. Two different String objects can hold the same characters; == would (incorrectly) compare whether they're the same object in memory.
  • edition >= other.getEdition() — note the direction: "greater than or equal to," not just "greater than." A Textbook can always substitute for an earlier or identical edition of itself.

Tracing the Example

Given from the question:

  • bio2015: title "Biology", price 49.75, edition 2
  • bio2019: title "Biology", price 39.75, edition 3
  • math: title "Calculus", price 45.25, edition 1

Trace through each call:

  • bio2019.getBookInfo()super.getBookInfo() returns "Biology-39.75", then + "-3""Biology-39.75-3"
  • bio2019.canSubstituteFor(bio2015) → titles match ("Biology" == "Biology"), and 3 >= 2 is truetrue
  • bio2015.canSubstituteFor(bio2019) → titles match, but 2 >= 3 is falsefalse
  • bio2015.canSubstituteFor(math) → titles don't match ("Biology" vs. "Calculus") → short-circuits to false immediately, edition is never even checked

All four results match the table given in the question.

Common Mistakes to Avoid

  • Trying to access title or price directly (e.g., title = bookTitle; inside Textbook's constructor). These fields are private to Book — this simply won't compile.
  • Forgetting super(...) entirely, which either fails to compile (if Book has no no-argument constructor) or leaves title/price uninitialized.
  • Rewriting the "title-price" formatting instead of calling super.getBookInfo(). It works, but duplicates logic that already exists — reusing the parent's method is both simpler and safer against future changes.
  • Using > instead of >= in canSubstituteFor. The rule specifically allows an equal edition to substitute for itself.
  • Comparing titles with == instead of .equals(). This is one of the most common AP CSA point losses across every FRQ that touches String comparison.

Key Takeaways

  • A subclass never accesses a parent's private fields directly — it goes through the parent's constructor (super(...)) and public methods instead.
  • Overriding a method to extend behavior (rather than fully replace it) almost always means calling super.methodName() first, then adding to the result.
  • String comparisons always use .equals(), never ==.

Related FRQs