AP CSA 3.3: Anatomy of a Class

AP CSA • Unit 3: Class Creation • Lesson 3.3

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.

Design Code Develop Code Analyze Code Document Code Use Computers Responsibly
Loading the interactive lesson. If this note stays visible, this preview is blocking JavaScript. Download the file and open it in a browser (Chrome), or view it on the live page, to use the editor, game, and quiz.
Learn
Practice
Assess
The short answer

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.

Learn

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 public or private for 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.

Scenario

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.

Skill focus: today you Design Code (decide what is hidden and what is exposed), Develop Code (write the header, the private attributes, and the public methods), and Analyze Code (predict what a class allows and what it refuses).
Learn

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;
    }
}
The conventions
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
Who can reach it
public inside AND outside
private inside the declaring class only
the wall is the class, not the object
Data encapsulation is this whole idea in one word: the implementation is hidden, and the only way in is through methods you wrote. Because you wrote them, you get to decide what is allowed.

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
The trade
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.

Watch out, the silent constructor: naming a constructor parameter the same as the instance variable and then writing 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.
Watch out, the guard that is not there: a mutator with no validation is just a public instance variable wearing a disguise. If 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

1. deposit ignores any value that is not positive. Starting at 300, after deposit(120) and deposit(-90), what is the balance?
2. Two objects are built from the same class. How many copies of an instance variable exist in total?
3. A method that may only be called from inside its own class is marked with which keyword? (one word)
Learn • error analysis

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

Wrong"getScore can round the value before returning it, or reset a counter once it has been read."
RightAn accessor reports and nothing else. The moment it changes state, calling it twice gives two different answers and no caller can trust it. If a value needs rounding, round it when it is stored or compute it in a separate method. On the exam, a getter with an assignment inside it is the answer to "what is wrong with this code".

Letting the return type drift from the field

Wrong"The field is a double, but returning an int from getPrice is close enough."
RightThe return type must match what the accessor reports. Returning 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

Wrong"setScore should return the new score so the caller can check it worked."
RightA mutator is normally 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

Wrong"The field is private, but I can still write obj.score = 5; from my test code."
RightYou cannot. Reaching a 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

Wrong"Everything private is safer, so all the methods should be private as well."
RightData is private by default; behavior is public when it is what the class offers and private when it is how the class does its job. A helper that both the constructor and a mutator call is a good private method. Making the accessors private too leaves a class nobody can use.
See it in memory

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.

LunchAccount a = new LunchAccount(500);
LunchAccount b = new LunchAccount(120);
a.deposit(250);
a.deposit(-400); // refused by the method
b.buy(300); // cannot afford, nothing changes
Stack (variables)
Heap (objects)
Encapsulation in memory: each LunchAccount object owns a private balance. Valid changes go through public methods; an invalid deposit and an unaffordable purchase are both refused, leaving every field untouched. Open in a browser to step through the animation.
Original interactive memory model. Every field shown is private: the only way any of them changed was through a method the class itself defines.
Practice • write and run real Java

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.

Problem 1 (Predict): Trace the wallScaffolded
Trace the commented segment by hand. Do not uncomment it. Print the two values it would print.
attempts: 0
Problem 2 (Predict): Boundary and separate copiesScaffolded
Trace the commented segment by hand. It prints four lines. Print all four, in order.
attempts: 0
Problem 3 (Complete): Declare the attributesScaffolded
The constructor and methods are written. Declare the two attributes so each slot owns its own copy and no outside code can reach them.
attempts: 0
Problem 4 (Complete): Write the private helperScaffolded
tick already calls a helper named isDone. Write that helper so it is usable inside the class and nowhere else.
attempts: 0
Problem 5 (Debug): Every panel has no areaScaffolded
It compiles, it runs, and every Panel reports an area of 0 no matter what you build it with. Find the defect and fix it.
attempts: 0
Problem 6 (Debug): The private field that is not protectedScaffolded
The specification says deposit must ignore any value that is not positive. balance is private, yet it still ends up wrong. Find the defect and fix it.
attempts: 0
Problem 7 (Write): Wall off the data, then guard the gateOpen-ended
Every header is written for you. Choose the access level that puts the data out of reach, then fill in the four bodies. The mutator is the only way in, so the rule has to live there.

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
Both ranges are inclusive at both ends. setTarget accepts 60 and 80; isComfortable accepts 68 and 74. Using > or < instead of >= or <= turns one boundary answer wrong and leaves the rest right.
attempts: 0
Problem 8 (Write): One rule, one place, called twiceOpen-ended
The constructor and the mutator need the same range rule. Write it once in the private helper and call that helper from both, rather than copying the logic and letting the two copies drift apart.

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
Write the range rule once. clamp is private on purpose: it is how this class does its job, not part of what it offers. Call it from both the constructor and the mutator rather than copying it.
attempts: 0
Practice • fluency

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.

Round 1 of 6. Final value of x?
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();
Round 2 of 6. Final value of x?
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();
Round 3 of 6. Final value of x?
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();
Round 4 of 6. Final value of x?
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();
Round 5 of 6. Final value of x?
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();
Round 6 of 6. Final value of x?
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();
Assess • twelve questions at AP difficulty

Multiple choice

Predict your answer before reading the options. Watch for the qualifier words. After you answer, the rationale explains every distractor.

Predict first
Predict the output before you read the options. What does this segment print?
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());
Spot the design defect
Every Cube built by this class reports a volume of 0, whatever arguments it is given. It compiles and runs. What is wrong?
public class Cube {
    private int side;

    public Cube(int side) {
        side = side;
    }

    public int volume() {
        return side * side * side;
    }
}
Analyze: I, II, III
Consider the class below and the two objects created from it. Which statements are true?
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()
NOT stem
Three of these are reasons to declare an instance variable private. Which is NOT?
public class Account {
    private int balance;
    // ...
}
Best answer
A specification says a Pass has a price that must never be set below zero. Which design follows the conventions of this course AND can actually enforce that rule?
public class Pass {
    // design goes here
}
Spot the design defect
The Counter class below compiles and runs. A reviewer says getCount is not a valid accessor. Why?
public class Counter {
    private int count;

    public Counter() {
        count = 0;
    }

    public void add() {
        count++;
    }

    public int getCount() {
        count++;
        return count - 1;
    }
}
Spot the design defect
A class stores a price as a double. Which accessor header is correct for it?
public class Item {
    private double price;

    // which header belongs here?
}
Predict first
A class declares a private instance variable. Another class writes the line shown. What happens?
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());
Analyze: I, II, III
A Payroll class is being written. Which of these members should be declared private?
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
Best answer
A specification says: setLimit changes the limit only when the new value is positive. Which header and body best match it?
public class Account {
    private int limit;

    // which version?
}
Predict first
Predict the value before you read the options. What does this segment print?
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());
Predict first
What does this segment print?
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());
Assess • free-response connection

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.

FRQ Practice (4 points): finish the BookCopy classOpen-ended
Every header is given. Fill in the seven TODOs. Three test lines are edge cases: lending a copy that is already out, returning one that was never taken, and a return late enough that the cap has to bite.

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
The cap is per return, not per copy. A single return may never add more than 500 cents, however late it is, so two very late returns can still total more than 500.
attempts: 0
Every student challenged

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
Review

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 private unless 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.
Review

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.

0 / 32 points
Editor 0/10 • Game 0/6 • Quiz 0/12 • FRQ 0/4

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.

Typically responds within 24 hours

Message Sent!

Thanks for reaching out. I'll get back to you within 24 hours.

🏫 Welcome, fellow educator!

I offer curriculum resources, practice materials, and study guides designed for AP CS teachers. Let me know what you're looking for — whether it's classroom materials, a guest speaker, or Teachers Pay Teachers resources.

Email

[email protected]

📚

Courses

AP CSA, CSP, & Cybersecurity

Response Time

Within 24 hours

Prefer email? Reach me directly at [email protected]