AP CSA 3.3: Anatomy of a Class
AP CSA 3.3: Anatomy of a Class
A class has four parts and one job: protect its own data. Private instance variables plus public methods you wrote is the whole idea, and it is the shape every FRQ 2 answer has to take.
A class has four parts: the header, its instance variables, its constructors, and its methods. The instance variables are private, so nothing outside the class can read or change them, and the methods are the only way in. An accessor reports a value and changes nothing; a mutator changes a value and usually returns void. That wall around the data is encapsulation, and it is what lets a class promise something and actually keep the promise.
What you will learn
- Name the four parts of a class and say what each one is for
- Write an accessor that reports a value without changing anything
- Write a mutator that enforces the class's rule before it stores anything
- Choose
publicorprivatefor data, constructors and methods, and defend the choice - Explain why a public instance variable makes a class unable to keep its own guarantee
- Spot the four accessor and mutator errors the exam reaches for again and again
Why this matters on the exam
Lesson 3.3 is where Unit 3 stops being about diagrams and starts being about Java. Under the 2025 CED the learning objective is stated as developing code to designate access and visibility constraints on classes, data, constructors and methods, and the essential knowledge is unusually prescriptive: in this course classes are always public, constructors are always public, and instance variables are private unless the specification says otherwise.
That prescriptiveness is a gift on the exam. It means a multiple-choice question can show you a class and expect you to say what is wrong with it in seconds, and it means free-response question 2 opens with a point you can bank: the class header and the private instance variables. Readers give that point for declaring the attributes at the right access level, before any logic is judged at all.
The errors that cost points here are small and repetitive. An accessor that quietly changes state. A getter whose return type does not match the field. A setter written to return something. Code that reaches for a private field from outside the class and does not compile. Learn those four shapes and a whole family of questions collapses into recognition.
The problem this solves
The CED asks it directly: how can a program be written to protect your account balance from being changed by accident? Leave the balance out in the open and any line of code anywhere can set it to a negative number, and nothing in the language will stop it. Put a wall around it, leave one door, and put the rule in the doorway, and the impossible state simply cannot happen. That wall is private, the door is a public method, and the pair of them is what the exam means by encapsulation.
The anatomy of a class, and the wall around it
A class has four parts and one job. The parts are the header, the instance variables, the constructors, and the methods. The job is to protect its own data, so that no code outside it can put the object into a state that should be impossible.
The four parts, in order
// 1. header: always public, keyword class public class LunchAccount { // 2. instance variables: private private int balance; // 3. constructor: always public public LunchAccount(int startCents) { balance = startCents; } // 4. methods: public interface, // private helpers public int getBalance() { return balance; } }
| class | always public |
| constructor | always public |
| instance variable | private |
| method | public or private |
Those first three are not style opinions. In this course they are the rule: classes are public, constructors are public, and instance variables are private unless a specification says otherwise.
What public and private actually mean
// inside the class: everything is reachable public boolean buy(int cents) { if (!canAfford(cents)) { return false; } balance -= cents; // private field: fine return true; } private boolean canAfford(int cents) { return cents > 0 && cents <= balance; } // outside the class: acct.buy(300); // public: allowed acct.balance = -500; // private: refused acct.canAfford(1); // private: refused
| public | inside AND outside |
| private | inside the declaring class only |
| the wall | is the class, not the object |
Why bother: the rule you can enforce
Make balance public and any line of code anywhere can write acct.balance = -500;. Nothing stops it. Make it private and the only road in is deposit, which you wrote, which can refuse.
// public data: no rule survives acct.balance = -500; // nothing stops this // private data + a method you control public void deposit(int cents) { if (cents <= 0) { return; } balance += cents; } acct.deposit(-500); // ignored, balance safe
| public data | anyone can break it |
| private data | you own the rules |
| the method | is where the rule lives |
One copy per object
Every object built from the class carries its own instance variables. Two accounts have two balances. Changing one leaves the other alone. The wall is per class, but the data is per object.
balance = balance; assigns the parameter to itself. The instance variable never changes, it keeps its default of 0, and the code compiles and runs without a word of complaint. Until 3.9 gives you this, the fix is to name the parameter something else.deposit adds whatever it is handed, making balance private bought you nothing.Vocabulary
| Term | Meaning |
|---|---|
| Encapsulation | Hiding a class's implementation so that outside code can only interact with it through methods the class provides. |
| Access modifier | The keyword public or private that decides who may reach a class, variable, constructor, or method. |
| public | Reachable from inside the declaring class and from any code outside it. |
| private | Reachable only from inside the declaring class. The wall is drawn around the class, not around each object. |
| Class header | The first line of the class, public class Name. In this course a class is always public. |
| Instance variable | An attribute each object owns its own copy of. Declare it private unless a specification says otherwise. |
| Accessor | A public method that reports a value without changing it, such as getBalance(). |
| Mutator | A public method that changes the object's state, such as deposit(). This is where a validation rule lives. |
| Helper method | A private method used only inside the class, to break a large behavior into smaller ones. |
Predict first, then check
deposit ignores any value that is not positive. Starting at 300, after deposit(120) and deposit(-90), what is the balance?Common misconceptions
Each of these is a real answer students give. Read the wrong version first and decide why it is wrong before you read the fix.
Thinking a getter may tidy up while it reports
Letting the return type drift from the field
double, but returning an int from getPrice is close enough."
int for a double field silently throws away the fractional part, and in Java it will not even compile without a cast. Read the field's type first, then write the header to match it.
Returning a value from a setter
void. Its job is the change, not a report; if the caller wants the value it calls the accessor. A method that both changes state and hands back a value is doing two jobs, and the AP subset expects the two to stay separate unless the specification asks for a boolean saying whether the change was allowed.
Believing private means private-ish
obj.score = 5; from my test code."
private member from outside its class is a compile-time error, not a warning and not a runtime problem. That is exactly why private is worth having: the compiler, not the programmer's good intentions, is what enforces the wall.
Treating private as a rule about methods too
See the wall in memory
Two LunchAccount objects, each with its own private balance. Watch a deposit land, an invalid deposit get refused by the method, and a purchase that cannot be afforded change nothing at all.
Live code editor
Eight problems, six scaffolded and two open-ended. Write Java and press Run to execute it. When you are ready, press Submit to test it against the expected output; the reference solution then appears underneath, next to your own code rather than on top of it. Hints are there if you are stuck, and attempts and hints are both tracked.
A Thermostat refuses to set its target outside a safe range. Every header is written for you; the access level and the four bodies are not.
Attribute
- target
- the target temperature in whole degrees. One per thermostat, and unreachable from outside the class.
Behaviors
- Thermostat(int startTarget)
- precondition: 60 to 80
- void setTarget(int t)
- changes the target only when t is 60 to 80. Any other value leaves it unchanged.
- int getTarget()
- reports the current target
- boolean isComfortable()
- true when the target is 68 to 74 inclusive
A ScoreEntry holds a test score that can never be stored outside 0 to 100. The constructor and the mutator both need that rule.
Attribute
- score
- the stored score, always 0 to 100 inclusive
Behaviors
- ScoreEntry(int s)
- stores s pulled into range: above 100 becomes 100, below 0 becomes 0
- void setScore(int s)
- stores s using the same rule
- int getScore()
- reports the stored score
- char letter()
- 90 and up A, 80 to 89 B, 70 to 79 C, 60 to 69 D, otherwise F
Encapsulation Arcade
Six quick rounds. Read the class and the client code, then type the final value. These are the six ways an encapsulation question goes wrong on the exam: a missing guard, a boundary, a private helper, separate copies, a self-assigning constructor, and a method that refuses.
public class A {
private int bal;
public A(int start) { bal = start; }
public void add(int n) { if (n <= 0) { return; } bal += n; }
public int get() { return bal; }
}
A a = new A(700);
a.add(150);
a.add(-200);
int x = a.get();
public class B {
private int bal;
public B(int start) { bal = start; }
private boolean ok(int n) { return n > 0 && n <= bal; }
public boolean buy(int n) { if (!ok(n)) { return false; } bal -= n; return true; }
public int get() { return bal; }
}
B b = new B(300);
b.buy(180);
int x = b.get();
public class C {
private int n;
public C(int start) { n = start; }
public int get() { return n; }
}
C p = new C(7);
C q = new C(2);
int x = p.get() + q.get();
public class D {
private int w;
public D(int w) { w = w; }
public int get() { return w; }
}
D d = new D(9);
int x = d.get();
public class E {
private int v;
public E(int start) { v = start; }
private int clamp(int n) { if (n > 100) { return 100; } if (n < 0) { return 0; } return n; }
public void set(int n) { v = clamp(n); }
public int get() { return v; }
}
E e = new E(50);
e.set(150);
int x = e.get();
public class F {
private int s;
private int used;
public F(int start) { s = start; used = 0; }
public boolean take(int n) { if (n > s) { return false; } s -= n; used++; return true; }
public int getUsed() { return used; }
}
F f = new F(10);
f.take(4);
f.take(20);
f.take(6);
int x = f.getUsed();
Multiple choice
Predict your answer before reading the options. Watch for the qualifier words. After you answer, the rationale explains every distractor.
public class Jar {
private int count;
public Jar(int start) {
count = start;
}
private boolean canTake(int n) {
return n > 0 && n <= count;
}
public boolean take(int n) {
if (!canTake(n)) {
return false;
}
count -= n;
return true;
}
public int getCount() {
return count;
}
}
Jar j = new Jar(12);
j.take(12);
j.take(1);
j.take(-3);
System.out.println(j.getCount());
public class Cube {
private int side;
public Cube(int side) {
side = side;
}
public int volume() {
return side * side * side;
}
}
public class Dial {
private int reading;
public Dial(int start) {
reading = start;
}
private void bump() {
reading++;
}
public void use() {
bump();
}
public int getReading() {
return reading;
}
}
Meter m = new Dial(5);
Meter n = new Dial(5);
m.use();
I. m and n each have their own reading
II. use() may call bump() because both are in the same class
III. code outside Dial may call m.bump()
public class Account {
private int balance;
// ...
}
public class Pass {
// design goes here
}
public class Counter {
private int count;
public Counter() {
count = 0;
}
public void add() {
count++;
}
public int getCount() {
count++;
return count - 1;
}
}
public class Item {
private double price;
// which header belongs here?
}
public class Cubby {
private int items;
public int getItems() {
return items;
}
}
// in a different class:
Cubby L = new Cubby();
L.items = 5;
System.out.println(L.getItems());
I. the hourlyRate instance variable
II. a roundToCents helper used by two other
methods inside the class
III. the getPay method the reporting screen calls
public class Account {
private int limit;
// which version?
}
public class Jar {
private int level;
public Jar() {
level = 0;
}
public void fill(int n) {
if (level + n <= 15) {
level += n;
}
}
public int getLevel() {
return level;
}
}
Jar j = new Jar();
j.fill(9);
j.fill(6);
j.fill(2);
System.out.println(j.getLevel());
public class Gauge {
private int level;
public Gauge(int start) {
level = clamp(start);
}
private int clamp(int n) {
if (n > 10) {
return 10;
}
if (n < 0) {
return 0;
}
return n;
}
public void set(int n) {
level = clamp(n);
}
public int getLevel() {
return level;
}
}
Gauge g = new Gauge(25);
g.set(-4);
g.set(10);
System.out.println(g.getLevel());
FRQ Practice
Free-response question 2 is Class Design. You are given a scenario and a table of interactions, and you build the class to match. This one is worth 4 points.
Every header below is written for you, because writing method bodies from nothing is 3.5. What 3.3 asks is the part that is here: put the data out of reach, and make each behavior the only legal way to change it. A copy that can be lent twice, or that a caller can reach into and mark returned, is the failure this lesson exists to prevent.
A school library tracks one physical copy of a book. It is lent and returned, it counts how many times it has been lent, and it accumulates late fees, with a cap so a single disastrous return cannot bankrupt a student.
| Call | Result |
|---|---|
| new BookCopy() | on the shelf, never lent, no fees |
| lend() | true the first time, false while it is already out |
| returnCopy(3) | shelves it and adds 3 x 25 = 75 cents |
| returnCopy(1) when it is on the shelf | false, and nothing changes |
| returnCopy(40) | adds 500, not 1000: one return is capped |
Scoring: 1 point for attributes that are genuinely out of reach, 1 point for the constructor starting every one of them, 1 point for lend and returnCopy refusing the impossible states rather than trusting the caller, and 1 point for the fee cap and the accessors.
A school library tracks one physical BookCopy. It is lent and returned, it counts how many times it has been lent, and it accumulates late fees with a cap.
Attributes, none reachable from outside
- onLoan
- whether this copy is currently lent out
- timesLent
- how many times this copy has been lent
- lateFeeCents
- total late fees accumulated on this copy
Behaviors
- BookCopy()
- on the shelf, never lent, owing nothing
- boolean lend()
- on the shelf: marks it out, counts the loan, returns true. Already out: changes nothing, returns false.
- boolean returnCopy(int daysLate)
- precondition: daysLate is 0 or more. Not on loan: changes nothing, returns false. Otherwise shelves it, adds 25 cents per day late, and returns true.
- int getTimesLent()
- how many times this copy has been lent
- int getLateFees()
- total late fees on this copy
- boolean isOnLoan()
- whether it is out right now
Choose your lane
Support
- Reread the Code and Memory panels
- Editor problems 1 to 3 with hints on
- Retry the quiz until 80%
- Use the FRQ method shell
Core
- All 8 editor problems
- Full game run
- The 12-question quiz once
- The FRQ connection
Challenge
- Open-ended problems 7 and 8 with no hints
- Rewrite one loop a different way
- Extend the FRQ
- Lead a class trace
Summary
A class is four parts with one job. The header names it and is always public in this course. The instance variables hold what each object knows and are private, so the class is the only thing that can change them. The constructor, also always public, gives those variables their starting values. The methods are the interface: public when they are what the class offers, private when they are how it does its work.
Two method shapes carry most of the exam's weight. An accessor reports a value, returns the same type as the field it reports, and changes nothing at all. A mutator changes a value, returns void unless a success flag is asked for, and is where the class's rule is enforced, because it is the only door in.
That combination is encapsulation, and its whole value is that the guarantee becomes real. A class with a private score and a clamping mutator can promise the score is between 0 and 100 and be believed. Make the field public and the promise evaporates, because any caller can write past the check without the class ever finding out.
Key takeaways
- Four parts: header, instance variables, constructors, methods.
- In this course classes are always public and constructors are always public.
- Instance variables are
privateunless the specification says otherwise. - An accessor reports and changes nothing; its return type matches the field.
- A mutator changes and returns
void, unless asked for a success flag. - A private helper is how a class avoids writing the same rule in two places.
- Touching a private member from outside is a compile error, which is the point.
Frequently asked questions
What is the difference between an accessor and a mutator?
An accessor, often called a getter, reports the value of an instance variable and changes nothing. Its return type matches the field it reports and its body is usually a single return. A mutator, often called a setter, changes an instance variable and normally returns void. The mutator is where validation lives, because it is the only route the outside world has to the data.
Why must instance variables be private in AP CSA?
Because a class can only enforce a rule if every change goes through its own code. The 2025 CED states it directly: it is good practice to designate the instance variables for attributes as private unless the class specification states otherwise. A public field lets a caller assign anything, so the validation inside the mutators never runs and the class's promise is worthless.
Can a method be private, and when should it be?
Yes. A private method can only be called from inside its own class, and that is exactly what you want for a helper that is part of how the class works rather than what it offers. The classic case is a rule needed in two places, such as a range check used by both the constructor and a mutator: write it once as a private helper and call it from both so the two can never drift apart.
What happens if I access a private variable from another class?
The program does not compile. This is a compile-time error in Java, which means you find out immediately rather than at runtime. AP multiple choice uses this constantly: a question shows client code touching obj.field and the correct answer is that the code will not compile, not that it prints something unexpected.
Does a setter ever return something other than void?
Sometimes, and only when the specification asks. A mutator that can legitimately refuse - lending a book that is already out, spending more than a balance - often returns a boolean saying whether the change happened. That is not a getter in disguise: it reports the outcome of the attempt, not the value of a field. Absent that requirement, a mutator is void.
Is the order of the parts of a class required by the exam?
No. Java does not care whether the instance variables come before or after the methods, and the exam will not take a point for ordering. Convention, and every worked example you will see, puts the instance variables first, then the constructors, then the methods, because a reader wants to know what an object holds before reading what it does. Follow it for readability, not for marks.
Related lessons
Unit 3: Class Creation
All 9 lessons in this unit. You are on 3.3.
- 3.1 Abstraction and Program Design
- 3.2 Impact of Program Design
- 3.3 Anatomy of a Class
- 3.4 Constructors
- 3.5 Methods: How to Write Them
- 3.6 Methods: Passing and Returning Object References
- 3.7 Class Variables and Methods
- 3.8 Scope and Access
- 3.9 The this Keyword
Test yourself on this unit
The rest of the course
Get in Touch
Whether you're a student, parent, or teacher — I'd love to hear from you.
Just want free AP CS resources?
Enter your email below and check the subscribe box — no message needed. Students get daily practice questions and study tips. Teachers get curriculum resources and teaching strategies.
Message Sent!
Thanks for reaching out. I'll get back to you within 24 hours.
Prefer email? Reach me directly at [email protected]