AP CSA Study Notes: Building Your Own Java Classes (Class Creation)
What a Class Is (and Why You Create One)
A class in Java is a programmer-defined type that bundles together data and the operations that work with that data. You can think of a class as a blueprint: it describes what information an object should store (its state) and what actions it can perform (its behavior). When you actually create an object from a class, that object is an instance of the class.
This matters because most interesting programs model real “things” that have both properties and actions: a Student has a name and GPA and can update their schedule; a BankAccount has a balance and can deposit or withdraw. If you only use primitive types (int, double, boolean) and arrays, your code quickly becomes messy—data that belongs together gets scattered across many variables and methods. Creating a class lets you keep related information together and makes your code easier to read, maintain, and extend.
A key mental model for AP CSA: each object you create from a class has its own copy of the class’s instance data. If you make two BankAccount objects, each has its own balance. The class definition is shared, but the instance variables live separately inside each object.
Objects have state and behavior
- State: stored in instance variables (also called fields).
- Behavior: implemented by methods.
When you call a method on an object, that method can:
- Read the object’s state.
- Change the object’s state.
- Return a result to the caller.
This is the core of object-oriented programming: you interact with an object through its methods, rather than directly manipulating its variables.
A first look: class vs. object
A class is the code you write once. An object is what you get when you use new.
public class Dog {
private String name;
public Dog(String theName) {
name = theName;
}
public void bark() {
System.out.println(name + " says woof!");
}
}
Using the class:
Dog d1 = new Dog("Miso");
Dog d2 = new Dog("Rex");
d1.bark(); // Miso says woof!
d2.bark(); // Rex says woof!
Even though both objects run the same method bark, they behave differently because their state (name) differs.
Exam Focus
- Typical question patterns:
- Identify whether a variable should be an instance variable or a local variable.
- Trace code that creates multiple objects and calls methods that update object state.
- Interpret a class’s purpose from its fields, constructors, and methods.
- Common mistakes:
- Treating a class as if it were an object (forgetting you must instantiate with
new). - Assuming two different objects “share” instance variables.
- Confusing what’s stored in an object (fields) with what’s stored in a method call (local variables).
- Treating a class as if it were an object (forgetting you must instantiate with
Anatomy of a Java Class (Parts You Must Get Right)
A Java class has a specific structure and vocabulary. Getting comfortable with the “shape” of a class helps you read AP questions quickly and write correct code under time pressure.
Class header and naming
A class declaration typically looks like this:
public class ClassName {
// fields, constructors, methods
}
publicmeans code in other classes can use this class.classintroduces a class definition.ClassNameshould follow Java convention: UpperCamelCase (e.g.,BankAccount,StudentRecord).
On the AP exam, you’ll usually be given a class name and asked to implement pieces inside it (fields, constructors, methods) or reason about how another class uses it.
Members: fields, constructors, methods
Inside the braces, you typically see:
- Instance variables (fields): store per-object state.
- Constructors: special methods that run when an object is created.
- Methods: define behavior.
Order doesn’t technically matter to the compiler, but a common style is: fields first, then constructors, then methods.
Access modifiers: controlling visibility
An access modifier controls where something can be used from.
private: only accessible inside the same class. This is the default choice for instance variables.public: accessible from outside the class. This is common for constructors and for methods that form the class’s “public API.”
Encapsulation (covered more deeply next) is the design principle behind this: you usually hide your data (private) and expose controlled operations (public).
Method signature basics
A method signature includes the method name and its parameter types (and, in common AP usage, you pay close attention to return type too).
public int getAge() { ... }
public void setAge(int newAge) { ... }
- Return type:
intvsvoid(no returned value). - Method name: lowerCamelCase by convention.
- Parameters: inputs the caller provides.
Comments and documentation
You’ll often see (and sometimes be expected to write) comments, including Javadoc-style comments:
/**
* Returns the current balance.
*/
public double getBalance() {
return balance;
}
On AP questions, comments frequently specify requirements (for example, “assume amount is positive” or “precondition: name is not null”). Those requirements matter when you decide whether to include error checking.
Exam Focus
- Typical question patterns:
- Fill in missing parts of a class skeleton: a field declaration, a constructor header, or a method header.
- Decide whether something should be
publicorprivatebased on how it’s used. - Identify whether a method should return a value or be
void.
- Common mistakes:
- Making instance variables
public, which breaks encapsulation and often contradicts prompt expectations. - Mismatching return types (e.g., returning a value from a
voidmethod or forgetting areturnin a non-voidmethod). - Forgetting semicolons on field declarations.
- Making instance variables
Instance Variables and Encapsulation (Protecting an Object’s State)
An instance variable (field) stores data that belongs to each object. If you create three Student objects, each object has its own name, id, etc.
Encapsulation is the idea that an object should manage its own data. In practice, AP CSA expects you to:
- Make fields
private. - Provide public methods to access or modify the state when appropriate.
Why fields are usually private
If fields were public, any code anywhere could do this:
account.balance = -1000000;
That’s dangerous because it can put an object into an invalid state. With private fields, you can enforce rules (often called class invariants): conditions that should always be true for a properly-functioning object.
For a BankAccount, an invariant might be “balance is never negative” (depending on the account rules). For a Time class, it might be “hours are 0–23.”
Accessors and mutators
- An accessor (getter) returns information without changing the object.
- A mutator (setter or modifier) changes the object’s state.
Example:
public class BankAccount {
private double balance;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
}
Notice deposit is a mutator, but it’s not necessarily named setBalance. In well-designed classes, you often prefer meaningful operations (deposit, withdraw) over raw setters because they better reflect the real-world actions and make it easier to keep the object valid.
Validation inside mutators
Mutators are where you enforce rules. A common AP pattern is:
- The prompt gives a precondition (“amount is positive”), in which case you may not need to check.
- Or the prompt says to handle invalid values, in which case you implement checks.
Here’s a setAge that enforces a rule:
public class Person {
private int age;
public void setAge(int newAge) {
if (newAge >= 0) {
age = newAge;
}
}
}
If you forget validation when it’s required, your class can enter an invalid state and later methods may behave incorrectly.
Choosing what to expose
Encapsulation does not mean “write getters and setters for everything.” It means “expose what users of the class need, and keep the rest hidden.”
For example, if the only legal way to change a game score is by adding points, you might omit setScore entirely and only provide addPoints(int p).
Exam Focus
- Typical question patterns:
- Write getters and/or methods that update private fields while preserving constraints.
- Identify which variables should be
privatevspublicin a class design. - Trace how a method call changes an object’s state.
- Common mistakes:
- Directly accessing a private field from another class (should use a public method).
- Writing a mutator that accidentally creates a local variable instead of updating the field (often due to shadowing).
- Forgetting to update the object’s state (e.g., computing a value but not storing it back into the field).
Constructors and Object Initialization (How Objects Start Life)
A constructor is a special block of code that runs when you create an object with new. Its job is to initialize the object’s instance variables so the object begins in a valid, usable state.
Constructors matter because, without them, your fields may start with default values that don’t match your intended meaning. Java does assign defaults (like 0 for int, null for object references), but relying on defaults often creates bugs—especially when a field should start with a meaningful value.
Constructor rules you need to know
A constructor:
- Has the same name as the class.
- Has no return type, not even
void. - Is typically
public.
Example:
public class Rectangle {
private int width;
private int height;
public Rectangle(int w, int h) {
width = w;
height = h;
}
}
Default constructor vs. no-argument constructor
Students often mix up two ideas:
- No-argument constructor: a constructor you explicitly write that takes no parameters.
- Default constructor: a constructor Java provides automatically only if you write no constructors at all.
If you write any constructor, Java does not automatically provide a no-argument one.
Example:
public class Point {
private int x;
private int y;
public Point(int xCoord, int yCoord) {
x = xCoord;
y = yCoord;
}
}
Here, new Point() is invalid because there is no no-argument constructor.
Overloaded constructors
Constructor overloading means providing multiple constructors with different parameter lists. This supports different ways of creating a valid object.
public class Point {
private int x;
private int y;
public Point(int xCoord, int yCoord) {
x = xCoord;
y = yCoord;
}
public Point() {
x = 0;
y = 0;
}
}
Now both new Point(3, 4) and new Point() work.
Using this to reduce duplicated code
When you have multiple constructors, you often want them to share initialization logic. Java allows one constructor to call another in the same class using this(...).
public class Point {
private int x;
private int y;
public Point(int xCoord, int yCoord) {
x = xCoord;
y = yCoord;
}
public Point() {
this(0, 0); // calls the other constructor
}
}
Important rule: this(...) must be the first statement in the constructor.
Initializing fields directly vs. in constructors
You can also assign a starting value at the field declaration:
private int score = 0;
This can be useful for constants or obvious defaults. But constructors are still important when initialization depends on parameters or when you want to enforce rules.
Exam Focus
- Typical question patterns:
- Write a constructor that correctly initializes all instance variables.
- Reason about what happens when a class defines one constructor but the code tries to call a different one.
- Implement overloaded constructors and/or use
this(...)to chain them.
- Common mistakes:
- Writing a return type on a constructor (turns it into a normal method, not a constructor).
- Forgetting that Java does not generate a default constructor if any constructor is written.
- Forgetting to initialize all fields (leaving them at default values unintentionally).
Writing Instance Methods (Behavior, Parameters, and Return Values)
A method is a named block of code that belongs to a class. When a method is an instance method (not static), it operates on a particular object—meaning it can access that object’s instance variables.
Methods are the main way outside code interacts with your objects. If encapsulation hides fields, methods are the “buttons and knobs” on the object.
Method headers: what each part means
Consider:
public int addPoints(int points) {
score += points;
return score;
}
public: can be called from other classes.int: returns anintvalue.addPoints: method name.(int points): one parameter namedpoints.
Parameters vs. instance variables
A parameter is a local variable that receives a value from the caller. It exists only during the method call.
An instance variable exists as long as the object exists.
A helpful analogy: parameters are like information you hand to a worker for one task; instance variables are like the worker’s permanent notebook.
Return values vs. void
A method with a non-void return type promises: “If you call me, I will produce a value of this type.” You must ensure every possible path returns something.
public boolean isPassing() {
return grade >= 60;
}
A void method performs an action but returns nothing. A common mistake is trying to use the result of a void method in an expression.
public void reset() {
score = 0;
}
// Wrong idea:
// int x = reset(); // reset returns nothing
Side effects and object state
A side effect is a change that persists after the method finishes. Updating an instance variable is a side effect.
This distinction matters in AP questions that ask you to predict state after a sequence of calls.
Example:
public class Counter {
private int value;
public Counter() {
value = 0;
}
public void increment() {
value++;
}
public int getValue() {
return value;
}
}
Using it:
Counter c = new Counter();
c.increment();
c.increment();
System.out.println(c.getValue()); // 2
Because increment mutates state, the change accumulates.
Local variables and scope
A local variable is declared inside a method (or inside a block like an if). It is only usable within that region—this is called its scope.
public int computeSomething(int x) {
int temp = x * 2;
if (temp > 10) {
int bonus = 5;
temp += bonus;
}
// bonus is NOT in scope here
return temp;
}
Scope issues show up a lot in debugging: if you declare a variable inside an if, you can’t use it outside.
Precondition and postcondition thinking
AP class-writing prompts often imply:
- Precondition: what must be true before calling a method.
- Postcondition: what will be true after the method finishes.
Even when you’re not asked to write formal pre/postconditions, thinking this way helps you implement methods correctly and avoid off-by-one or “forgot to update field” errors.
Exam Focus
- Typical question patterns:
- Implement a method that updates instance variables and/or returns a computed value.
- Trace method calls that mutate state across multiple objects.
- Identify scope errors or missing
returnstatements.
- Common mistakes:
- Returning too early (e.g., inside a loop) when the method should finish processing first.
- Confusing a parameter with an instance variable (especially when names are similar).
- Declaring a local variable with the same name as a field and accidentally using the wrong one.
Using this and Avoiding Shadowing Bugs
The keyword this is a reference to the “current object”—the specific instance whose method or constructor is running. It matters most when you need to be explicit about which variable you mean.
Why this exists
Inside an instance method, you can usually refer to fields directly:
public int getScore() {
return score;
}
But problems arise when a parameter or local variable has the same name as an instance variable. This is called shadowing: the local name “covers up” the field name within that scope.
Shadowing example (common AP bug)
public class Student {
private String name;
public Student(String name) {
name = name; // BUG: assigns parameter to itself
}
}
This code compiles, but it doesn’t do what you want. The assignment uses the parameter on both sides, so the field name never changes and remains null.
Fix it with this:
public class Student {
private String name;
public Student(String name) {
this.name = name; // field = parameter
}
}
this in methods
Same idea for setters:
public void setName(String name) {
this.name = name;
}
You don’t have to name the parameter the same as the field, but many Java programmers do, and AP questions often include that style—so recognizing this.field is important.
Returning this (advanced but occasionally useful)
Sometimes methods return the current object to allow chaining:
public Counter incrementAndReturn() {
value++;
return this;
}
AP CSA usually doesn’t emphasize fluent interfaces, but understanding that this is a reference to the object can help you reason about return types and method calls.
Exam Focus
- Typical question patterns:
- Debug or complete a constructor or setter where shadowing occurs.
- Explain which variable is being referenced in a method (
namevsthis.name). - Trace object state after calling methods that use parameters with the same names as fields.
- Common mistakes:
- Writing
x = x;in constructors or setters. - Thinking
thiscreates a new object (it does not; it refers to the existing one). - Using
this(...)incorrectly in constructors (it must be the first statement).
- Writing
Static Variables and Static Methods (Class-Level vs Object-Level)
Not everything belongs to a single object. Sometimes a value or behavior should be shared across all instances of a class. In Java, you do that with static.
Instance vs. static: the key difference
- Instance members belong to an object. You access them through an object reference.
- Static members belong to the class itself. There is only one copy shared by all objects.
Example scenario: you want to count how many Student objects have been created.
public class Student {
private static int numStudents = 0;
private String name;
public Student(String name) {
this.name = name;
numStudents++;
}
public static int getNumStudents() {
return numStudents;
}
}
Here:
numStudentsis shared across allStudentobjects.getNumStudentsis static, so you call it on the class:Student.getNumStudents().
Why static methods can’t access instance variables directly
A static method does not run “on” a particular object. There is no implied this. So it can’t directly use instance variables like name, because which object’s name would it mean?
Inside a static method, you can:
- Use static variables.
- Use parameters and local variables.
- Create objects and use them explicitly.
static final constants
A common pattern is to store constants using static final:
public class Circle {
public static final double PI = 3.14159;
}
finalmeans it cannot be reassigned.staticmeans there is one shared copy.
AP problems may use constants for readability and to avoid “magic numbers.”
Calling static vs. instance
- Instance call:
myObject.methodName() - Static call:
ClassName.methodName()
Java technically allows calling static methods through an object reference, but it’s poor style and can confuse readers. AP questions usually prefer the class name.
Exam Focus
- Typical question patterns:
- Determine whether a variable or method should be static based on whether it’s per-object or shared.
- Trace code where a static variable changes as multiple objects are constructed.
- Identify illegal uses of instance variables inside static methods.
- Common mistakes:
- Treating a static field as if each object has its own copy.
- Trying to use instance variables in a static method without an object reference.
- Forgetting
staticon a counter variable that’s meant to track all instances.
The toString Method and Meaningful Object Output
When you print an object reference with System.out.println(someObject);, Java calls that object’s toString method. If you don’t define one, you get the default toString from Object, which is usually not human-friendly.
Why toString matters
A good toString makes debugging and output easier. In AP CSA, it’s common to be asked to implement toString so that printing an object produces a specific format.
Overriding toString
To override means “provide your own version of a method that already exists in a superclass.” Every class implicitly extends Object, so toString is always available.
A typical override:
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
Now:
Point p = new Point(3, 4);
System.out.println(p); // (3, 4)
Formatting and string concatenation
AP questions often require an exact string format. Small differences (extra spaces, missing punctuation) can make an answer incorrect.
When building strings:
- Use
+to concatenate. - Be careful about spaces and commas.
- Remember that concatenating with a
Stringturns primitives into text automatically.
@Override annotation
The @Override annotation is not required, but it’s helpful. If you accidentally misspell toString (like toStirng), @Override will trigger a compile-time error—catching the mistake early.
Exam Focus
- Typical question patterns:
- Implement
toStringto match a required output format. - Determine what gets printed when an object is passed to
System.out.println. - Compare output with and without a custom
toString.
- Implement
- Common mistakes:
- Using the wrong method header (must be
public String toString()with no parameters). - Returning something that isn’t a
String. - Formatting errors: missing parentheses, extra spaces, or wrong order of fields.
- Using the wrong method header (must be
Reference Variables, Aliasing, and null (How Objects Are Actually Stored)
In Java, variables that refer to objects do not store the entire object “inside” the variable. Instead, they store a reference (think: an address or a remote control) to an object that lives elsewhere in memory.
This matters a lot when you create classes because many AP questions test whether you understand:
- Two variables can refer to the same object (aliasing).
- Passing an object to a method can allow that method to mutate the object.
- A reference can be
null(meaning it refers to no object).
Aliasing: two references, one object
Counter c1 = new Counter();
Counter c2 = c1; // no new object created
c1.increment();
System.out.println(c2.getValue()); // prints 1
Because c1 and c2 refer to the same object, changes through one reference are visible through the other. This surprises students who expect assignment to “copy” the object.
null references
A reference variable can hold null, meaning “no object.”
Point p = null;
If you try to call a method on null, you get a NullPointerException.
p.toString(); // runtime error
On the AP exam, you may be asked to reason about whether code can throw a NullPointerException, especially when objects are conditionally created.
== vs. logical equality (brief but important)
For object references:
==checks whether two references point to the same object.- Many classes provide an
.equals(...)method to check logical equality (same content).
AP class-creation tasks more often focus on == for aliasing and tracing, but you should at least recognize that == is about identity for objects.
Passing objects to methods: Java is pass-by-value
Java passes arguments by value. That means the method receives a copy of whatever is stored in the variable.
- For primitives, the copied value is the number/boolean/char itself.
- For objects, the copied value is the reference.
So the method gets a copy of the reference, but that copy still points to the same object—so the method can mutate the object.
Example:
public static void addOne(Counter c) {
c.increment();
}
Counter myCounter = new Counter();
addOne(myCounter);
System.out.println(myCounter.getValue()); // 1
However, if the method reassigns its parameter to a new object, that reassignment does not change the caller’s reference:
public static void resetToNew(Counter c) {
c = new Counter(); // only changes local copy of the reference
}
Counter myCounter = new Counter();
myCounter.increment();
resetToNew(myCounter);
System.out.println(myCounter.getValue()); // still 1
This distinction (mutating the object vs. reassigning the parameter) shows up in AP tracing questions.
Exam Focus
- Typical question patterns:
- Trace code with multiple references to the same object and predict final field values.
- Determine whether a
NullPointerExceptioncan occur. - Analyze the effect of passing an object to a method that mutates it.
- Common mistakes:
- Thinking
Counter c2 = c1;makes a separate copy of the object. - Assuming reassigning a parameter inside a method changes the caller’s variable.
- Calling a method on a reference that might be
null.
- Thinking
Putting It Together: Designing a Cohesive Class (From Requirements to Code)
On many AP class-creation problems, you’re given an English description (or partial code) and asked to implement missing pieces. The challenge is less about syntax and more about translating requirements into a clean class design.
A well-designed AP-style class typically has:
- A small set of private fields that represent essential state.
- Constructors that guarantee the object starts valid.
- Public methods that provide necessary behaviors while maintaining invariants.
Step-by-step design process (AP-friendly)
When you’re given a prompt, a reliable approach is:
- Identify the state: What information must each object remember over time?
- These become your private instance variables.
- Identify required initialization: What values must be set when the object is created?
- These become constructor parameters and assignments.
- Identify behaviors: What must the object be able to do?
- These become methods. Decide which should return values and which should be
void.
- These become methods. Decide which should return values and which should be
- Enforce rules: Are there constraints on the fields?
- Add validation where required by the prompt.
Worked example: Battery
Suppose you need a class representing a rechargeable battery with:
- A current charge level.
- A maximum capacity.
- Methods to drain and recharge without exceeding bounds.
Implementation:
public class Battery {
private int charge;
private int capacity;
public Battery(int capacity) {
this.capacity = capacity;
charge = capacity; // start full
}
public int getCharge() {
return charge;
}
public void drain(int amount) {
if (amount > 0) {
charge -= amount;
if (charge < 0) {
charge = 0;
}
}
}
public void recharge(int amount) {
if (amount > 0) {
charge += amount;
if (charge > capacity) {
charge = capacity;
}
}
}
@Override
public String toString() {
return charge + "/" + capacity;
}
}
What to notice:
- Fields are private.
- The constructor sets a meaningful initial state.
drainandrechargeenforce bounds, keeping the object valid.
How AP prompts communicate requirements
AP free-response and practice questions often include statements like:
- “Assume
amountis positive.” (You can skip the check.) - “If the parameter value is invalid, the method should not change the object.” (You must check.)
- “The method returns …” or “The method updates …” (decides return type and side effects.)
Reading these carefully is part of the skill: many wrong answers come from implementing a correct-looking method that doesn’t match the described behavior.
Exam Focus
- Typical question patterns:
- Implement one or more methods based on a written specification and existing fields.
- Write constructors and methods that maintain constraints (bounds, nonnegative values, etc.).
- Interpret comments describing preconditions and required effects.
- Common mistakes:
- Ignoring a required condition (e.g., method should do nothing on invalid input).
- Updating a local variable instead of the instance variable.
- Violating encapsulation by making fields public or returning internal mutable data when not intended.
Testing and Tracing Class Behavior (How You Know Your Class Works)
When you create a class, you usually test it by writing another class (often called a driver or tester) that constructs objects and calls methods. AP questions often simulate this by giving you a main method or a short code snippet and asking for output or final field values.
Building a simple test driver
Here’s a tester for the Battery class:
public class BatteryTester {
public static void main(String[] args) {
Battery b = new Battery(10);
System.out.println(b); // 10/10
b.drain(3);
System.out.println(b.getCharge()); // 7
b.recharge(100);
System.out.println(b); // 10/10
}
}
Even if AP doesn’t require you to write main methods often, thinking like a tester helps you avoid common implementation mistakes. For example, draining below zero and recharging above capacity are boundary cases that quickly reveal whether you enforced your invariants.
Tracing object state
A common AP task is to trace how values change across a sequence of calls.
Example:
Counter a = new Counter();
Counter b = new Counter();
a.increment();
b.increment();
b.increment();
a = b;
a.increment();
System.out.println(b.getValue());
Reasoning:
- After first three increments:
ahas 1,bhas 2. a = b;makesarefer to the same object asb.a.increment();increments that shared object from 2 to 3.- Printing
b.getValue()prints 3.
The key step is recognizing where aliasing begins.
Using toString for debugging
A good toString can act like a built-in “status report” for the object. On AP questions, toString often exists precisely so that object state can be observed easily via printing.
Exam Focus
- Typical question patterns:
- Predict output from code that constructs objects, calls methods, and prints results.
- Trace state changes, especially when references are reassigned.
- Determine whether methods are pure (no side effects) or mutators.
- Common mistakes:
- Forgetting that
a = b;does not copy an object. - Assuming printing an object prints its fields automatically (it prints
toString). - Missing boundary-condition effects (values clamped to min/max, invalid inputs ignored, etc.).
- Forgetting that
Common AP-Style Class Creation Prompts (How They’re Typically Framed)
While the exact class varies, AP class-creation questions tend to reuse a few “shapes” of tasks. Recognizing these shapes helps you quickly decide what to write.
Pattern 1: “Write a constructor and initialize fields”
You’re given fields and asked to complete a constructor so that:
- Each field is set from a parameter, or
- Some fields are computed from parameters, or
- Default starting values are assigned.
A typical twist is shadowing: the parameters may have the same names as fields, requiring this.field = field; style assignments.
Pattern 2: “Write an accessor and a mutator with a rule”
You may need to:
- Return a field value.
- Update a field only when the parameter meets a condition.
- Clamp a value (not below 0, not above max).
Pattern 3: “Complete a method that updates state and returns something”
These methods often:
- Update a field.
- Return the updated value, a boolean indicating success, or a computed result.
Example: a withdraw might return true if it succeeded and false otherwise.
Pattern 4: “Implement toString”
Often requires exact formatting and uses multiple fields.
Exam Focus
- Typical question patterns:
- Fill-in-the-blank implementations inside a class: constructor, method bodies,
toString. - Mixed tracing + implementation: implement a method, then predict output using it.
- Identify and fix bugs related to encapsulation, shadowing, and aliasing.
- Fill-in-the-blank implementations inside a class: constructor, method bodies,
- Common mistakes:
- Writing code that compiles but doesn’t match the written specification.
- Overcomplicating: adding extra fields or methods not asked for, which can introduce errors.
- Missing subtle requirements in comments (especially “does not change state when…”).