SECTION 1
Historical Context & Motivation
Before object-oriented programming (OOP) emerged, software developers organized code primarily as sequences of procedures operating on shared data structures. As programs scaled into millions of lines—think air-traffic control systems or banking platforms—this procedural paradigm made it increasingly difficult to isolate bugs, reuse components, or reason about program state. The concept of a class arose to bundle related data and the operations that act upon it into a single, self-contained unit, fundamentally reshaping how humans design software.
1967 • Simula 67
1972 • Smalltalk
1983 • C++ Emerges
1995 • Java Released
Java's design decision to make the class the fundamental unit of code means that understanding class anatomy is not optional—it is the prerequisite for everything else in AP Computer Science A. Every program you write, every data structure you build, and every algorithm you implement will live inside a class. The central question this lesson addresses is: What are the essential components of a Java class, and how do they work together to model real-world entities?
SECTION 2
Core Principles & Definitions
A Java class is a blueprint that specifies two things: the state an object holds (its data) and the behavior it can perform (its methods). When you instantiate a class with the new keyword, the JVM allocates memory for a distinct object whose instance variables are independent of every other object created from the same class. The following principles govern how classes are structured in Java.
Instance Variables (Fields)
private to enforce encapsulation.Constructors
new. They initialize instance variables to valid starting states.Methods
Access Modifiers
public exposes members to all classes; private restricts access to the declaring class only, enabling information hiding.Encapsulation
SECTION 3
Visual Explanation — Class Structure Diagram
Student class with three private instance variables (violet), a constructor (cyan), accessor and mutator methods (green and pink), and a toString method (amber). Notice how the private fields are accessible only through the public methods—this is encapsulation in action.The visual reinforces a critical organizational pattern: instance variables appear first, followed by constructors, and finally methods. While the Java compiler does not enforce this ordering, the AP exam's Free Response Questions consistently follow this convention, and graders expect you to do the same. Each instance variable is declared private so that external code cannot modify the object's state arbitrarily; instead, controlled access is provided through public methods.
SECTION 4
How It Works — From Class to Object
Declaration vs. Instantiation vs. Initialization
Creating an object from a class involves three distinct conceptual steps that Java often compresses into a single statement. Consider Student s = new Student("Ada", 11, 3.9);. First, declaration creates the reference variable s of type Student. Second, instantiation occurs when new allocates heap memory for the object. Third, initialization happens when the constructor executes, assigning the arguments to the instance variables. After this line, s holds a reference (an address) pointing to the newly created Student object on the heap.
The Role of the Constructor
A constructor has the same name as its class and no return type—not even void. If you write no constructor at all, Java provides a default constructor with no parameters that initializes numeric fields to 0, booleans to false, and object references to null. However, the moment you define any constructor, the compiler no longer supplies the default, so you must explicitly write a no-argument constructor if you still want one. A class may have multiple overloaded constructors that differ in their parameter lists, enabling flexible object creation.
The this Keyword
Inside any instance method or constructor, this is an implicit reference to the current object. It is most commonly used when a constructor parameter name shadows an instance variable: this.name = name; distinguishes the field from the parameter. On the AP exam, using this is not required when there is no ambiguity, but it is considered good practice and will never cost you points.
Separate tickets provide an analogy for separate objects. In the Dog example, each instance has its own name and age fields.
Suppose two Dog instances store Milo, age 2, and Luna, age 4. Each name and age belongs to its own instance. Changing one object’s fields does not automatically change the other object.
SECTION 5
Detailed Breakdown — Access, Scope & Encapsulation
| Component | Access Modifier | Scope / Visibility |
|---|---|---|
| Instance variable | private | Accessible only within the class |
| Constructor | public | Callable by any class; invoked with new |
| Accessor method | public | Returns field value; does not modify state |
| Mutator method | public | Modifies one or more fields; often void return |
| Local variable | N/A (not a member) | Exists only within the method/block where declared |
Summary of class member access and scope
A common source of AP exam errors is confusing instance variables with local variables. Instance variables persist for the lifetime of the object and are accessible from every non-static method in the class. Local variables are created when their enclosing method is called and destroyed when the method returns. If a local variable shares a name with an instance variable, the local variable shadows the instance variable within that method, unless you use this to disambiguate.
SECTION 6
Worked Example — Building a BankAccount Class
Let us design a complete BankAccount class, walking through each component as it would appear on an AP Free Response Question. The class must store an account holder's name and balance, allow deposits and withdrawals (rejecting overdrafts), and provide a string summary.
Worked example
- 1
Step 1 — Declare Instance Variables
We need two pieces of state: the holder's name and current balance. Both are declaredprivateto enforce encapsulation.private String owner;private double balance; - 2
Step 2 — Write the Constructor
The constructor accepts initial values for both fields. We usethisto distinguish instance variables from parameters of the same name.public BankAccount(String owner, double balance) { this.owner = owner; this.balance = balance; } - 3
Step 3 — Accessor Methods
We provide getters so client code can read, but not write, the fields directly.public String getOwner() { return owner; }public double getBalance() { return balance; } - 4
Step 4 — Mutator Methods with Validation
Thedepositmethod adds to the balance only if the amount is positive. Thewithdrawmethod subtracts only if sufficient funds exist, guarding against overdraft.public void deposit(double amt) { if (amt > 0) balance += amt; }public void withdraw(double amt) { if (amt > 0 && amt <= balance) balance -= amt; } - 5
Step 5 — toString Method
OverridingtoStringallows meaningful output when the object is printed. This is not strictly required on the AP exam but is tested in MCQs.public String toString() { return owner + ": $" + balance; }
SECTION 7
Common Pitfalls & Comparisons
| Concept | Correct Usage | Common Mistake |
|---|---|---|
| Constructor return type | No return type keyword at all | Writing void before the constructor name, turning it into a regular method |
| Field access modifier | private for instance variables | Using public fields, violating encapsulation |
| Default constructor | Provided only when no constructors are defined | Assuming it still exists after writing a parameterized constructor |
| Accessor vs. mutator | Accessor returns data and is side-effect-free | An accessor that modifies state or a mutator that returns a value when it should be void |
| Variable shadowing | Use this.field = param to disambiguate | Writing field = field which assigns the parameter to itself |
Frequent errors on the AP exam and how to avoid them
SECTION 8
Connection to Advanced Topics
The anatomy of a class you have learned here is the foundation upon which every advanced AP Computer Science A topic rests. Inheritance allows one class to extend another, inheriting its fields and methods while adding or overriding functionality. Polymorphism leverages method overriding so that a single reference variable can invoke different behaviors depending on the actual object type at runtime. Abstract classes and interfaces (interfaces are tested lightly on the AP exam) build on the class concept by defining contracts that subclasses must fulfill.
| This Lesson | Next Steps |
|---|---|
| Writing a single class with private fields | Extending a class with extends (inheritance) |
| Defining constructors | Calling super() in subclass constructors |
| Accessor and mutator methods | Method overriding and dynamic dispatch (polymorphism) |
| Instance variables belong to one object | static variables shared across all instances (not on AP subset but useful) |
toString() for readable output | equals() and compareTo() for object comparison |
Mastering class anatomy now will pay dividends in Units 5 through 9 of the AP course. When you encounter an FRQ that asks you to design a class hierarchy, you will be applying the same principles—private fields, public constructors, accessor/mutator methods—at every level of the hierarchy. The only addition is the mechanism of inheritance that connects parent and child classes.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
public class Dog {
private String breed;
}
Which of the following statements is true about the field breed?- A. It can be accessed directly by any class in the same program.
- B. It can only be accessed by methods defined within the Dog class.
- C. It is automatically initialized to the empty string "" when a Dog object is created.
- D. It must be declared static because it is private.
Show answer (B)
private modifier restricts access to the declaring class only, so only methods within Dog can read or write breed. A is wrong because private fields cannot be accessed by other classes. C is wrong because object reference fields default to null, not the empty string. D is wrong because private and static are independent modifiers; there is no requirement that private fields be static.Question 2: BASIC CALCULATION
public class Counter {
private int count;
public Counter() { count = 0; }
public Counter(int start) { count = start; }
public void increment() { count++; }
public int getCount() { return count; }
}
What is the output of the following code?
Counter c1 = new Counter();
Counter c2 = new Counter(5);
c1.increment();
c1.increment();
c2.increment();
System.out.println(c1.getCount() + " " + c2.getCount());- A.
2 6 - B.
2 5 - C.
3 6 - D.
0 5
Show answer (A)
c1 starts at 0 and is incremented twice → 2. c2 starts at 5 and is incremented once → 6. B is wrong because it fails to apply the increment to c2. C is wrong because c1 is only incremented twice, not three times. D is wrong because it ignores all increments entirely. Each object maintains its own independent count field—this is a key property of instance variables.Question 3: INTERMEDIATE
public class Rectangle {
private double width;
private double height;
public Rectangle(double width, double height) {
/* missing code */
}
public double getArea() {
return width * height;
}
}
Which replacement for /* missing code */ correctly initializes both fields?- A.
width = width; height = height; - B.
this.width = width; this.height = height; - C.
Rectangle.width = width; Rectangle.height = height; - D.
double width = width; double height = height;
Show answer (B)
this is required to refer to the instance variables. A is wrong because width = width assigns the parameter to itself due to shadowing, leaving the instance variable at its default value of 0.0. C is wrong because Rectangle.width would refer to a static field named width, which does not exist. D is wrong because it declares new local variables that shadow the parameters, resulting in a compile error or meaningless self-assignment.Question 4: APPLIED
Thermostat that models a home thermostat. The class must have:
• A private instance variable temperature (int) representing the target temperature in °F.
• A constructor that takes an int parameter and sets the temperature, clamped between 50 and 90 inclusive.
• An accessor method getTemp() that returns the current temperature.
• A mutator method adjust(int delta) that adds delta to the temperature but keeps the result within the 50–90 range.
• A toString() method that returns a string in the format "Thermostat: 72°F".Show answer
public class Thermostat {
private int temperature;
public Thermostat(int temp) {
temperature = Math.max(50, Math.min(90, temp));
}
public int getTemp() {
return temperature;
}
public void adjust(int delta) {
temperature += delta;
temperature = Math.max(50, Math.min(90, temperature));
}
public String toString() {
return "Thermostat: " + temperature + "°F";
}
}
Rubric breakdown: (1) Class header public class Thermostat and private int temperature. (2) Constructor clamps via conditional or Math.min/Math.max. (3) getTemp() returns temperature. (4) adjust modifies and re-clamps. (5) toString concatenates correctly.Question 5: CRITICAL THINKING
public class Score {
public int points;
public Score(int p) {
points = p;
}
public void bonus(int extra) {
points += extra;
}
}
(a) Identify the design flaw and explain why it violates OOP best practices.
(b) Show how client code could exploit this flaw.
(c) Rewrite the class to fix the flaw, adding any necessary methods.Show answer
points is declared public, which violates encapsulation. Any external class can read or modify points without going through a method, bypassing any validation.
(b) Client code exploit: Score s = new Score(100); s.points = -9999; — this sets points to an invalid negative value with no check.
(c) Fixed class:
public class Score {
private int points;
public Score(int p) { points = Math.max(0, p); }
public int getPoints() { return points; }
public void bonus(int extra) {
if (extra > 0) points += extra;
}
}
Rubric: (1 pt) identifies the public field as the flaw. (1 pt) shows direct assignment like s.points = -9999. (1 pt) rewrites with private field, getter, and validated mutator.