SECTION 1
Historical Context & Motivation
Before the rise of object-oriented programming (OOP), software engineers wrote programs as long sequences of instructions—an approach known as procedural programming. As codebases grew from hundreds of lines to hundreds of thousands, procedural code became notoriously difficult to maintain, extend, and debug. Data and the functions that operated on that data were loosely coupled, making it easy for one part of a program to corrupt another part's state inadvertently. The fundamental insight that emerged in the 1960s was deceptively simple: organize programs around the real-world entities they model, bundling data and behavior together into self-contained units called objects.
1967 • Simula 67
1972 • Smalltalk
1985 • C++ Released
1995 • Java Launches
2003 • AP CS A Adopts Java
The evolution from procedural to object-oriented thinking gave rise to a powerful question that sits at the heart of this lesson: if a class defines what something is and what it can do, how do we create individual, living instances of that class that hold their own unique data? Understanding the distinction between a class as a blueprint and an object as a concrete instance is the gateway to mastering Java and the AP Computer Science A exam.
SECTION 2
Core Principles & Definitions
In Java, the relationship between a class and an object mirrors the relationship between an architectural blueprint and the house built from it. A class is a programmer-defined data type that specifies the attributes (instance variables) and behaviors (methods) that its objects will have. An object is a specific instance of a class that occupies memory at runtime and holds its own copies of those attributes. The process of creating an object from a class is called instantiation, and it is accomplished in Java using the new keyword. Each object created from the same class shares the same structure—the same set of instance variables and methods—but maintains its own independent state.
Class (Blueprint)
Object (Instance)
new keyword. It lives in the heap memory and has its own copies of instance variables holding unique values.Constructor
new is called. It initializes the object's instance variables. Its name always matches the class name and it has no return type.Reference Variable
The null Value
null. Calling a method on a null reference throws a NullPointerException at runtime.KEY TAKEAWAY
new) to produce an actual cookie you can eat (an object you can use).SECTION 3
Visual Explanation: Class to Object
new Dog(...) call creates a separate object on the heap with its own instance variable values. The reference variables on the stack (dog1, dog2, dog3) store memory addresses that point to their respective objects. A reference set to null points to nothing.The diagram above illustrates the fundamental mechanism at work. The Dog class on the left defines the structure—three instance variables (name, age, breed) and two methods—but it holds no data of its own. Each invocation of new Dog(...) allocates fresh memory on the heap and invokes the constructor to populate the instance variables with concrete values. Notice that dog1, dog2, and dog3 share the same structure but contain completely different data—"Buddy" versus "Luna" versus "Max." The reference variables in the stack panel do not contain the objects themselves; they hold addresses (shown symbolically as 0x3A, 0x7F, 0xB2) that point to the objects in heap memory. This distinction between the reference and the object it references is essential for understanding assignment, equality, and parameter passing in Java.
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 4
How Instantiation Works in Java
The Anatomy of an Object Creation Statement
In Java, creating an object involves a single statement that performs two distinct tasks: declaration of a reference variable and instantiation of the object. The general syntax is:
OBJECT CREATION SYNTAX
ClassName (left side) = the declared type of the reference variable. variableName = the name of the reference. new = the keyword that allocates memory and triggers the constructor. ClassName(arguments) = the constructor call that initializes the new object.
Consider the following concrete examples using Java's built-in String class and a custom Student class:
EXAMPLE: STRING OBJECT
Creates a new String object on the heap. The reference variable greeting stores the address of that object. (Note: Java also supports the shorthand String greeting = "Hello, AP CS!"; which uses the string pool, but the new form illustrates general object creation.)
EXAMPLE: CUSTOM OBJECT
Calls the Student constructor with three arguments that map to instance variables name, gradeLevel, and gpa. The reference s1 now points to the newly created Student object in memory.
What Happens Behind the Scenes
- Step 1 — Memory allocation: The JVM allocates space on the heap large enough to hold all instance variables defined in the class.
- Step 2 — Default initialization: Instance variables receive default values (0 for numeric types,
falsefor booleans,nullfor reference types). - Step 3 — Constructor execution: The constructor body runs, overwriting defaults with the supplied argument values.
- Step 4 — Reference returned: The
newexpression evaluates to the memory address of the newly created object, which is stored in the reference variable.
Overloaded Constructors
new Student("Bob") would call a one-parameter constructor, while new Student("Alice", 12, 3.9) calls the three-parameter version.SECTION 5
Reference Variables, Aliasing & null
One of the most common pitfalls for AP students is confusing the reference variable with the object itself. When you write Dog dog1 = new Dog("Buddy", 3, "Lab");, the variable dog1 is not the object—it is a reference that points to the object. This has profound implications for assignment and equality. When you execute Dog dog4 = dog1;, you do not create a second Dog; instead, dog4 and dog1 now both point to the same object in memory. This phenomenon is called aliasing, and it means that modifying the object through one reference is visible through the other.
Dog dog4 = dog1;, both references hold the same address (0x3A). Calling dog4.setAge(4) mutates the single object, so dog1.getAge() also returns 4.The == Operator vs. .equals()
Because reference variables store addresses rather than data, the == operator compares addresses—it checks whether two references point to the same object, not whether two objects contain the same data. To compare the contents of two objects, use the .equals() method. For example, dog1 == dog4 evaluates to true because they are aliases, but if you create Dog dog5 = new Dog("Buddy", 3, "Labrador"), then dog1 == dog5 evaluates to false even though the data is identical, because they reside at different heap addresses.
| Expression | Result | Explanation |
|---|---|---|
dog1 == dog4 | true | Both reference the same object (aliased). |
dog1 == dog5 | false | Different objects, even with identical data. |
dog1.equals(dog5) | Depends on class | Returns true only if the class overrides equals() to compare field values. |
dog1 == null | false | dog1 references an object, so it is not null. |
Comparison of == and .equals() for object references
Two variables can provide access to one shared object. Copying a reference creates another access path; it does not duplicate the object.
Two new expressions create Fido and Rex. After the assignments, d1 refers to Rex, d3 refers to Fido and d2 is null. Both objects remain reachable; == compares reference identity, while equals depends on the class’s implementation.
SECTION 6
Worked Example: Tracing Object Creation
Consider the following code that uses a Rectangle class with instance variables width and height, a constructor Rectangle(double w, double h), and methods getArea() and toString(). We want to trace through the following statements and determine what is printed.
CODE TO TRACE
Tracing Object Creation and Method Calls
- 1
Step 1 — First instantiation
Rectangle r1 = new Rectangle(4.0, 5.0);allocates a new Rectangle object on the heap withwidth = 4.0andheight = 5.0. The reference variabler1stores the address of this object.r1 → Rectangle{width=4.0, height=5.0} - 2
Step 2 — Second instantiation
Rectangle r2 = new Rectangle(3.0, 7.0);creates a separate Rectangle object withwidth = 3.0andheight = 7.0. This object occupies a different heap location than the first.r2 → Rectangle{width=3.0, height=7.0} - 3
Step 3 — Aliasing assignment
Rectangle r3 = r1;does not create a new object. It copies the address stored inr1intor3. Now both r1 and r3 reference the same Rectangle{4.0, 5.0} object.r3 is an alias of r1 (same heap address) - 4
Step 4 — Method calls and output
r1.getArea()returns 4.0 × 5.0 = 20.0.r2.getArea()returns 3.0 × 7.0 = 21.0.r1 == r3evaluates totruebecause they share the same address.r1 == r2evaluates tofalsebecause they reference different objects.Output: 20.0, 21.0, true, false
SECTION 7
Common Pitfalls & Best Practices
Students preparing for the AP exam frequently encounter the same set of mistakes when working with objects and references. The table below catalogs these pitfalls alongside the correct approach, giving you a diagnostic checklist to consult when debugging your code or answering free-response questions.
| Pitfall | What Goes Wrong | Correct Approach |
|---|---|---|
Forgetting the new keyword | Declaring Dog d; without new leaves d as null. Calling d.bark() throws NullPointerException. | Always initialize with new ClassName(args) before using the reference. |
| Using == for content equality | s1 == s2 returns false even when both objects hold identical data, because == compares references. | Use .equals() for content comparison (especially with String objects). |
| Unintended aliasing | Assigning one reference to another creates a shared reference, not a copy. Mutating through one alias surprises code using the other. | Create a new object with the same data if you need an independent copy. |
| Wrong constructor arguments | Passing arguments in the wrong order or of the wrong type causes a compile-time error or, worse, silent logical bugs. | Match the number, type, and order of parameters exactly as defined in the constructor signature. |
| Calling methods on null | If a reference is null and you call a method on it, the program crashes at runtime with a NullPointerException. | Check for null before calling methods: if (obj != null). |
Common mistakes when working with objects and references in Java
KEY TAKEAWAY
SECTION 8
Connection to Advanced Concepts
The class-and-object model you are learning for the AP exam forms the foundation for virtually every advanced topic in Java and software engineering. Understanding how objects work prepares you for inheritance (where a subclass extends a parent class, and objects of the subclass are also instances of the parent), polymorphism (where a reference of a parent type can point to an object of a subclass type), and interfaces (where multiple unrelated classes can share a common API). At the systems level, understanding heap allocation and references connects to garbage collection, memory management, and performance optimization—topics you will encounter in data structures and operating systems courses.
| AP CS A Concept | Advanced Extension | Why It Matters |
|---|---|---|
| Objects & instantiation | Design patterns (Factory, Singleton, Builder) | Patterns control how and when objects are created in large systems. |
| Reference variables | Garbage collection & memory management | When no reference points to an object, the JVM reclaims its memory automatically. |
| Constructors | Inheritance & super() chaining | Subclass constructors must invoke a superclass constructor, creating a chain of initialization. |
| Class as a type | Polymorphism & interfaces | A reference of type Animal can point to a Dog object—runtime behavior depends on the actual object type. |
| == vs .equals() | hashCode() contract & collections | HashMap and HashSet rely on consistent equals/hashCode implementations to locate objects. |
How AP-level object concepts scale to advanced topics
As you progress beyond the AP exam, you will find that the mental model of classes as blueprints and objects as instances is not merely a pedagogical simplification—it is the architectural foundation upon which frameworks like Spring, Android, and enterprise Java are built. Every web request in a Spring application, every Activity in an Android app, and every node in a data structure is an object instantiated from a class. Mastering this concept now creates a transferable mental framework that scales naturally to advanced coursework and professional software development.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
- A. A class is a specific instance of an object that occupies memory at runtime.
- B. A class defines a blueprint of instance variables and methods; an object is a specific instance created from that blueprint using the new keyword.
- C. An object is the source code definition, and a class is what is created when the program runs.
- D. A class and an object are the same thing; both terms refer to a data type in Java.
Show answer (B)
new keyword, occupying heap memory with its own data. Choice A reverses the relationship. Choice C swaps the definitions of class and object. Choice D incorrectly conflates the two—a class is a type definition, while an object is a runtime entity.Question 2: BASIC CALCULATION
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1;
What are the values of s1 == s2 and s1 == s3?- A.
trueandtrue - B.
trueandfalse - C.
falseandtrue - D.
falseandfalse
Show answer (C)
new String(...) creates a distinct object on the heap. Therefore s1 and s2 reference different objects, making s1 == s2 false (== compares references, not content). The assignment s3 = s1 copies the reference, making s3 an alias of s1, so s1 == s3 is true. Choice A incorrectly assumes == compares content. Choice B reverses the true/false results. Choice D incorrectly claims aliases are not equal by ==.Question 3: INTERMEDIATE
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void translate(int dx, int dy) {
x += dx;
y += dy;
}
public String toString() {
return "(" + x + ", " + y + ")";
}
}
What is printed by the following code segment?
Point p1 = new Point(2, 3);
Point p2 = p1;
p2.translate(5, -1);
System.out.println(p1);- A.
(2, 3) - B.
(7, 2) - C.
(5, -1) - D. A NullPointerException is thrown.
Show answer (B)
Point p2 = p1 makes p2 an alias of p1—both reference the same Point object. When p2.translate(5, -1) is called, x becomes 2 + 5 = 7 and y becomes 3 + (−1) = 2 on the shared object. Printing p1 shows (7, 2) because p1 and p2 point to the same modified object. Choice A ignores the mutation. Choice C confuses the translation deltas with absolute coordinates. Choice D is wrong because both p1 and p2 are properly initialized.Question 4: APPLIED
3 ptsBankAccount class has the following constructor and methods:
• BankAccount(String owner, double balance) — constructs an account with the given owner name and initial balance.
• void deposit(double amount) — adds amount to the balance.
• double getBalance() — returns the current balance.
Write a code segment that:
(a) Creates two BankAccount objects, one for "Alice" with $500.00 and one for "Bob" with $1200.00.
(b) Deposits $250.00 into Alice's account.
(c) Prints the balance of each account on separate lines.Show answer
new keyword with correct constructor arguments.
BankAccount alice = new BankAccount("Alice", 500.00);
BankAccount bob = new BankAccount("Bob", 1200.00);
Point 2 — Correct method call for deposit: The deposit method must be called on Alice's reference with the correct argument.
alice.deposit(250.00);
Point 3 — Correct output of balances: Both balances must be printed using getBalance(), with Alice's showing 750.00 and Bob's showing 1200.00.
System.out.println(alice.getBalance());
System.out.println(bob.getBalance());
Output: 750.0 and 1200.0. The deposit only affects Alice's object because alice and bob are separate instances.Question 5: CRITICAL THINKING
4 ptspublic class Roster {
private Student[] students;
private int count;
public Roster(int capacity) {
students = new Student[capacity];
count = 0;
}
/** Adds a student to the roster.
* Precondition: count < students.length
*/
public void addStudent(String name, int grade) {
// Part (a): implement this method
}
/** Returns the number of students in the given grade.
*/
public int countInGrade(int targetGrade) {
// Part (b): implement this method
}
}
The Student class has constructor Student(String name, int grade) and method int getGrade().
(a) Write the body of addStudent. It should create a new Student object and add it to the next available position in the array, then increment count.
(b) Write the body of countInGrade. It should iterate over the students in the roster and return the number whose grade matches targetGrade.Show answer
new Student(name, grade) to instantiate the object. Passing name and grade in the correct order is required.
Point 2 — Part (a): Correctly stores object and increments count:
Assigns the new Student to students[count] and then increments count (or uses count++ as the index). Sample solution:
students[count] = new Student(name, grade);
count++;
Point 3 — Part (b): Correct loop iterating over filled portion of the array:
Must iterate from 0 to count (exclusive), not students.length, to avoid NullPointerException on unfilled slots. Uses a for or while loop.
Point 4 — Part (b): Correct comparison and return of count:
Calls students[i].getGrade() and compares with == (since int is a primitive). Accumulates a counter and returns it. Sample solution:
int total = 0;
for (int i = 0; i < count; i++) {
if (students[i].getGrade() == targetGrade) {
total++;
}
}
return total;
This problem tests the student's ability to instantiate objects in context (creating a Student inside a method that receives primitive/String parameters), store object references in an array, and call methods on those stored references—core skills for the AP CS A free-response section.SUMMARY
Summary
Summary
A class is a blueprint that defines instance variables (state) and methods (behavior). An object is a concrete instance created by the new keyword, which allocates memory on the heap and invokes a constructor to initialize the object's state. Multiple objects can be instantiated from the same class, each with its own independent data. A reference variable stores the memory address of an object, not the object itself—assigning one reference to another creates an alias, not a copy.
The == operator compares references (addresses), while .equals() compares object content. A reference that has not been assigned to an object holds the value null, and calling a method on null triggers a NullPointerException. These foundational concepts—instantiation, reference semantics, aliasing, and null—form the basis for every object-oriented topic on the AP Computer Science A exam, from writing constructors and calling methods to understanding inheritance and polymorphism.