FRQ
› csapa
CombinedTable: 2021 FRQ 2
A step-by-step solution to the 2021 AP CSA FRQ 2 (CombinedTable), covering object composition, storing object references, and computing values that update automatically in Java.
Two restaurant tables pushed together form the scenario behind this AP Computer Science A free-response question — you build a brand-new class that wraps two existing objects and computes values that stay in sync even after those objects change.
What This FRQ Tests
- AP CSA units: Unit 5 (Writing Classes) — this one leans on composition (a class that stores other objects as fields) rather than inheritance
- Core skill: writing a complete class from scratch, including its fields, constructor, and every method the prompt describes
- Secondary skill: recognizing that storing a reference to an object (instead of copying its data out at construction time) is what makes computed values automatically stay current
- Official category: "Classes" — always FRQ 2 on the AP CSA exam
The Setup
- The given
SingleTableclass has:int getNumSeats()— always 4 or moreint getHeight()— the table's height in centimetersdouble getViewQuality()— the view quality, which can change after the object is createdvoid setViewQuality(double value)— changes the view quality (already written, not part of this problem)
- You're asked to write the entire
CombinedTableclass, which represents twoSingleTableobjects pushed together:- A constructor:
CombinedTable(SingleTable t1, SingleTable t2) boolean canSeat(int numCustomers)— can this combined table seat that many people?double getDesirability()— how desirable is this combined table?
- A constructor:
- The rules:
- A
CombinedTableseats two fewer people than the sum of its two tables' seat counts (seats are lost when the tables are pushed together). - If the two tables are the same height, desirability is the average of their view qualities.
- If the two tables are different heights, desirability is that same average, minus 10.
- A
Building the CombinedTable Class
Step-by-Step Approach
- Declare two
private SingleTablefields to hold the two tables being combined. - Write a constructor that takes both
SingleTableobjects as parameters and simply stores them — don't pull out and copy their seat counts, heights, or view qualities into separate fields. - Write
canSeat(int numCustomers): add the two tables' seat counts together, subtract2, and check whethernumCustomersis less than or equal to that total. - Write
getDesirability(): compute the average of the two tables' current view qualities, then check whether the two tables' heights are equal to decide whether to subtract10.
The Code
public class CombinedTable
{
private SingleTable table1;
private SingleTable table2;
public CombinedTable(SingleTable t1, SingleTable t2)
{
table1 = t1;
table2 = t2;
}
public boolean canSeat(int numCustomers)
{
int totalSeats = table1.getNumSeats() + table2.getNumSeats() - 2;
return numCustomers <= totalSeats;
}
public double getDesirability()
{
double average = (table1.getViewQuality() + table2.getViewQuality()) / 2;
if (table1.getHeight() == table2.getHeight())
{
return average;
}
else
{
return average - 10;
}
}
}
Why Each Piece Matters
- Storing
table1andtable2as fields, not copying their data out — this is the single most important decision in this problem. Becausetable1andtable2hold references to the actualSingleTableobjects, callingtable1.getViewQuality()insidegetDesirability()always reads whatever that table's view quality is right now — including changes made throughsetViewQuality()after theCombinedTablewas constructed. numCustomers <= totalSeats, not<— the rule says a table "can seat" a given number of customers, which includes seating exactly that many.- Dividing by
2for the average — bothgetViewQuality()calls returndouble, so this division is already floating-point; no cast is needed here (unlike problems that start fromintdata). ==for comparing heights —getHeight()returns a primitiveint, and primitives are always compared with==, never.equals(). (Contrast this with comparingStringobjects, which always use.equals().)
Tracing the Example
Given from the question:
t1: 4 seats, view quality60.0, height74t2: 8 seats, view quality70.0, height74t3: 12 seats, view quality75.0, height76
Trace through each call:
| Call | Result | Why |
|---|---|---|
c1 = new CombinedTable(t1, t2) |
— | c1 stores references to t1 and t2 |
c1.canSeat(9) |
true |
total seats = 4 + 8 − 2 = 10; 9 ≤ 10 |
c1.canSeat(11) |
false |
11 > 10 |
c1.getDesirability() |
65.0 |
heights equal (74 = 74) → average of 60.0 and 70.0 |
c2 = new CombinedTable(t2, t3) |
— | c2 stores references to t2 and t3 |
c2.canSeat(18) |
true |
total seats = 8 + 12 − 2 = 18; 18 ≤ 18 |
c2.getDesirability() |
62.5 |
heights differ (74 ≠ 76) → average of 70.0 and 75.0 (72.5), minus 10 |
t2.setViewQuality(80) |
— | changes t2's view quality directly |
c2.getDesirability() |
67.5 |
average of 80.0 and 75.0 (77.5), minus 10 |
That last row is the whole point of the problem: c2 was never told about the change to t2 — it just re-reads t2.getViewQuality() every time getDesirability() is called, because it stored a reference to t2 itself rather than a snapshot of its data.
Common Mistakes to Avoid
- Copying
getViewQuality(),getHeight(), orgetNumSeats()into new fields inside the constructor (e.g.,viewQuality1 = t1.getViewQuality();). This "freezes" the data at construction time —c2.getDesirability()would keep returning62.5forever, even aftert2.setViewQuality(80)is called, which contradicts the example. - Forgetting the
- 2seat adjustment, or subtracting it from the wrong place (e.g., insidegetNumSeats(), which isn't yours to modify). - Applying the
-10penalty when heights are equal instead of when they differ — double check which branch of theifmatches which rule. - Using
.equals()to compareintheights..equals()is for objects likeString; primitives likeintcompare with==.
Key Takeaways
- When a new class is built out of existing objects, store references to those objects as fields — don't copy their data into new fields, or the new class will silently go stale whenever the original objects change.
- A method that reports on other objects' current state should call their getters inside itself, every time it runs, rather than caching a result.
- Primitive values (
int,double,boolean) compare with==; object values likeStringcompare with.equals().