SECTION 1
Historical Context & Motivation
Every program, from a simple calculator to a sophisticated web application, must store and manipulate data. In the earliest days of computing, programmers worked directly with raw memory addresses and binary values, a process that was both error-prone and extraordinarily tedious. The concept of a variable—a named container for a piece of data—emerged as one of the most transformative abstractions in programming language design, allowing humans to reason about data symbolically rather than numerically. Coupled with data types, which classify what kind of data a variable holds and what operations are legal on that data, these concepts form the bedrock upon which all Java programs are built.
1957 • FORTRAN Introduces Named Variables
X and TOTAL instead of raw memory addresses, pioneering the variable concept still used today.1970 • Pascal Popularizes Strong Typing
1983 • C++ Brings Object Types
1995 • Java Defines Its Type System
int is always 32 bits, regardless of the hardware.Java's decision to be a statically typed language means that every variable must be declared with a specific type before it can be used, and the compiler enforces type rules at compile time rather than at runtime. This design raises an essential question: how does Java's type system classify data, and how do the rules governing primitive types differ from those governing reference types? Mastering this distinction is not merely academic—it is the foundation for understanding parameter passing, method return values, and the behavior of objects throughout the AP Computer Science A curriculum.
SECTION 2
Core Principles & Definitions
Before writing any Java code, you need a precise vocabulary for the concepts that govern how data is declared, stored, and accessed. Java organizes its entire type system around a fundamental split: primitive types store actual values directly in memory, while reference types store addresses (references) that point to objects located elsewhere in memory. Understanding this distinction is essential for predicting how assignment, comparison, and method calls behave.
Variable Declaration
int score;. The compiler reserves the appropriate amount of memory and enforces that only compatible values can be stored.Initialization
int score = 95;. Local variables in Java must be initialized before use; the compiler will reject code that reads an uninitialized local variable.Primitive Types
int, double, boolean, etc.) that store values directly. The AP exam focuses on int, double, and boolean.Reference Types
String, arrays, and all user-defined classes. A reference variable holds the memory address of the object, not the object itself.Type Casting
int → double) automatically but requires explicit narrowing casts (e.g., (int) 3.7) that may lose data.KEY TAKEAWAY
int mailbox holds a single whole number, while a reference-type mailbox holds a slip of paper with a forwarding address to a larger package (the object) stored in a warehouse (the heap). Assigning one reference variable to another copies only the forwarding slip, not the package, which is why two reference variables can point to the exact same object.SECTION 3
Visual Explanation — Primitive vs. Reference Memory Model
age, gpa, passed) hold their values directly on the stack. The two reference variables (name, greeting) store memory addresses that point to String objects stored on the heap.The diagram above illustrates the fundamental memory distinction that the AP exam frequently tests. When you declare int age = 17;, the value 17 is stored directly in the variable's memory slot on the stack. In contrast, when you write String name = "Alice";, the variable name does not contain the characters "Alice"—instead, it holds a reference (essentially a memory address) that points to a String object on the heap. This is why comparing two String variables with == checks whether they point to the same object, not whether they contain the same sequence of characters—a nuance that the .equals() method resolves.
Java assignment copies a value. For primitive variables this is the primitive value; for object variables it is a reference to an object.
After x is changed to 9, y keeps its copied value of 42. For String variables, assignment copies a reference: reassigning a to "world" leaves b referring to the unchanged "hello" object.
SECTION 4
How It Works — Declaration, Assignment, and Casting
Variable Declaration and Assignment Syntax
In Java, every variable declaration follows the pattern type variableName = value;. The compiler uses the declared type to determine how many bytes to allocate and what operations are permissible. Declaration and initialization can occur on the same line, or the variable can be declared first and assigned later, though local variables must be initialized before they are read.
DECLARATION SYNTAX
Where type is any primitive or reference type, variableName follows camelCase naming conventions, and expression evaluates to a compatible type.
Integer Division and Truncation
One of the most common pitfalls on the AP exam involves integer division. When both operands of the division operator are int values, Java performs integer division, which truncates the decimal portion rather than rounding. For example, 7 / 2 evaluates to 3, not 3.5. If at least one operand is a double, the result is a double: 7.0 / 2 yields 3.5.
INTEGER DIVISION RULE
To force floating-point division, cast one operand: (double) a / b. The modulus operator % returns the remainder: 7 % 2 evaluates to 1.
Widening and Narrowing Casts
Java automatically performs widening conversions that preserve information, such as promoting an int to a double when necessary. However, a narrowing conversion—converting a double to an int—requires an explicit cast because the fractional part is discarded. Writing int x = (int) 9.99; assigns 9 to x—the decimal portion is truncated, not rounded.
CASTING SYNTAX
Examples: (int) 3.14 → 3, (double) 5 → 5.0. Casting truncates toward zero for conversions from floating-point to integer.
SECTION 5
Detailed Breakdown — AP-Testable Data Types
While Java defines eight primitive types in total, the AP Computer Science A exam focuses on three primitives and several reference types. The table below provides a comprehensive breakdown of each type's characteristics, range, and common usage patterns that you should commit to memory for both the multiple-choice and free-response sections of the exam.
| Type | Category | Size | Range / Details | Example |
|---|---|---|---|---|
int | Primitive | 32 bits | −2,147,483,648 to 2,147,483,647 | int count = 42; |
double | Primitive | 64 bits | ≈ ±1.8 × 10³⁰⁸; ~15 decimal digits of precision | double pi = 3.14159; |
boolean | Primitive | 1 bit (logical) | true or false only | boolean done = false; |
String | Reference | Varies | Immutable sequence of characters; compare with .equals() | String s = "Hi"; |
| Class types | Reference | Varies | Any user-defined or library class; default value is null | Scanner sc = new Scanner(System.in); |
AP-testable data types with their categories, sizes, and usage
int, double, boolean) and the main reference type categories. Note the key behavioral differences summarized at the bottom.Notice that the hierarchy diagram emphasizes a critical behavioral difference: primitive variables store their actual values, so the == operator compares values directly. Reference variables store addresses, so == compares whether two variables point to the same object in memory—not whether the objects are logically equivalent. This distinction is the single most common source of bugs tested on the AP exam, particularly with String comparisons.
SECTION 6
Worked Example — Tracing Variable State
The following example walks through a realistic code segment, tracing the values of variables after each statement. This type of code-tracing exercise appears frequently on the AP exam's multiple-choice section, where you must mentally execute Java statements and predict output.
Tracing Assignments, Casting, and Integer Division
- 1
Step 1 — Declare and Initialize Variables
Consider the following code segment:int a = 17;int b = 5;double c = 2.5;After these statements,aholds 17,bholds 5, andcholds 2.5.a = 17, b = 5, c = 2.5 - 2
Step 2 — Perform Integer Division
int d = a / b;Since bothaandbareintvalues, Java performs integer division: 17 / 5 = 3 with remainder 2. The fractional part is truncated.d = 3 (not 3.4) - 3
Step 3 — Compute Modulus
int e = a % b;The modulus operator returns the remainder of integer division: 17 % 5 = 2 because 17 = 3 × 5 + 2.e = 2 - 4
Step 4 — Mixed-Type Arithmetic with Widening
double f = a + c;Theintvaluea(17) is automatically widened to 17.0 before addition. The result is 17.0 + 2.5 = 19.5, stored as adouble.f = 19.5 - 5
Step 5 — Explicit Narrowing Cast
int g = (int) f;The explicit cast(int)truncates the decimal portion of 19.5, yielding 19. Without the cast, this line would cause a compile error because adoublecannot be implicitly narrowed to anint.g = 19 - 6
Step 6 — Casting Before Division
double h = (double) a / b;The cast applies toafirst, converting it to 17.0. Now the division is 17.0 / 5, which is floating-point division, yielding 3.4. Compare this to Step 2, where the same operands produced 3.h = 3.4
SECTION 7
Primitive vs. Reference — A Side-by-Side Comparison
Many AP exam questions hinge on the behavioral differences between primitive and reference types—particularly in the context of assignment, comparison, and method parameter passing. The following table consolidates these differences into a single reference that clarifies common misconceptions.
| Characteristic | Primitive Types | Reference Types |
|---|---|---|
| What is stored | The actual value (e.g., 42, 3.14, true) | A memory address pointing to the object on the heap |
| == operator | Compares values — 5 == 5 is true | Compares addresses — two objects with identical content may return false |
| Content comparison | Use == (it already compares values) | Use .equals() method |
| Assignment (=) | Copies the value — changes to one copy don't affect the other | Copies the reference — both variables now point to the same object |
| Default value | 0 (int), 0.0 (double), false (boolean) for instance variables | null for instance variables |
| Method parameters | Pass by value — the method receives a copy; the original is unaffected | Pass by value of the reference — the method can modify the object's state via the copied reference |
Behavioral comparison of primitive and reference types
KEY TAKEAWAY
SECTION 8
Connection to Advanced Topics
The concepts of variables and data types are not isolated topics—they form the foundation for nearly every advanced topic in the AP Computer Science A curriculum. Understanding how data is stored, typed, and passed informs your reasoning about object-oriented design, polymorphism, and algorithm analysis. The table below maps each core concept from this lesson to its downstream applications.
| Foundation Concept | Advanced Application | Why It Matters |
|---|---|---|
| Primitive vs. reference | Autoboxing (Integer, Double) | ArrayList cannot hold primitives; Java automatically wraps int → Integer |
| Reference assignment | Aliasing and mutability | Two references to the same ArrayList mean changes through one appear in the other |
| Type declarations | Polymorphism and inheritance | A variable declared as a superclass type can hold a subclass object at runtime |
| Integer division | Array index calculations | Binary search uses integer division to find midpoints; truncation behavior is critical |
| Type casting | Downcasting in inheritance | Casting an Object to a specific class type requires explicit syntax and may throw ClassCastException |
How foundational variable concepts connect to advanced AP CSA topics
As you progress through the course, you will encounter these concepts repeatedly. The distinction between storing values versus storing references resurfaces in every discussion of arrays, ArrayLists, and object interactions. Mastering variables and data types now provides the mental model you need to reason confidently about more complex constructs like inheritance hierarchies, interface implementations, and recursive data structures.
Looking Ahead
String and Math classes. Every method call, parameter, and return value you encounter will reinforce the primitive-vs-reference distinction you have learned here.SECTION 9
Practice Problems
Question 1: CONCEPTUAL
String s1 = "hello";
String s2 = s1;
String s3 = new String("hello");
Which of the following correctly describes the result of evaluating s1 == s2 and s1 == s3?- A.
s1 == s2istrueands1 == s3istrue - B.
s1 == s2istrueands1 == s3isfalse - C.
s1 == s2isfalseands1 == s3isfalse - D.
s1 == s2isfalseands1 == s3istrue
Show answer (B)
s2 = s1 copies the reference stored in s1 to s2, so both point to the exact same String object in the string pool; therefore s1 == s2 is true. However, new String("hello") explicitly creates a new String object on the heap, so s3 points to a different object even though the content is identical. Since == compares references (addresses), not content, s1 == s3 is false. Option A is wrong because new forces a distinct object. Option C is wrong because s1 and s2 do share the same reference. Option D reverses the correct outcomes.Question 2: BASIC CALCULATION
int x = 23;
int y = 7;
System.out.println(x / y + " r " + x % y);- A.
3.285714 r 2 - B.
3 r 2 - C.
3.0 r 2.0 - D.
4 r 2
Show answer (B)
x and y are both int, 23 / 7 performs integer division yielding 3 (truncated, not rounded), and 23 % 7 yields the remainder 2. The string concatenation produces "3 r 2". Option A is wrong because integer division does not produce a decimal result. Option C is wrong because the operands are int, not double. Option D is wrong because integer division truncates toward zero, not rounds up.Question 3: INTERMEDIATE
double a = 11;
int b = 4;
int c = (int) (a / b) + a / (double) b;
What happens when this code is compiled?- A. The code compiles and
cis assigned the value 4 - B. The code compiles and
cis assigned the value 5 - C. The code compiles and
cis assigned the value 5.75 - D. The code does not compile because of a type mismatch
Show answer (D)
a / b is 11.0 / 4 = 2.75 (since a is a double). The cast (int) (a / b) truncates this to 2. Second, a / (double) b is 11.0 / 4.0 = 2.75. Adding these gives 2 + 2.75 = 4.75, which is a double. The result cannot be stored in int c without an explicit narrowing cast, so the compiler reports an error: possible lossy conversion from double to int. Options A and B are wrong because the code never compiles. Option C is wrong for the same reason, and also misidentifies the type of c as capable of holding a double value.Question 4: APPLIED
3 ptspublic static double toCelsius(int fahrenheit)
{
double celsius = 5 / 9 * (fahrenheit - 32);
return celsius;
}
The method compiles but returns incorrect values. Explain why the method produces wrong results and provide a corrected version of the calculation line. Your corrected code must use casting or a double literal to fix the bug.Show answer
5 / 9 performs integer division because both 5 and 9 are int literals. Integer division truncates, so 5 / 9 evaluates to 0, causing the entire expression to evaluate to 0 regardless of the fahrenheit value.
Point 2 — Explain the fix: At least one operand of the division must be a double so that floating-point division is performed. This can be accomplished by using a double literal (5.0 or 9.0) or by casting one operand, e.g., (double) 5 / 9.
Point 3 — Provide correct code: Any of the following are acceptable:
double celsius = 5.0 / 9 * (fahrenheit - 32);
double celsius = (double) 5 / 9 * (fahrenheit - 32);
double celsius = 5 / 9.0 * (fahrenheit - 32);
All three ensure that 5/9 evaluates to approximately 0.5556 rather than 0.Question 5: CRITICAL THINKING
4 ptspublic static String describeChange(double oldPrice, double newPrice) that computes the percent change from oldPrice to newPrice, truncates it to a whole number using a cast, and returns a String of the form "Change: X%" where X is the truncated integer percent change. For example, if oldPrice is 80.0 and newPrice is 95.0, the percent change is 18.75, which truncates to 18, and the method returns "Change: 18%". The formula for percent change is ((newPrice − oldPrice) / oldPrice) × 100.Show answer
String), correct parameter types (both double), and is public static.
Point 2 — Correct percent change calculation: Computes (newPrice - oldPrice) / oldPrice * 100 using double arithmetic (since both parameters are double, this happens automatically). The expression correctly evaluates to a floating-point percent change value.
Point 3 — Correct use of casting to truncate: Uses (int) cast to convert the double percent change to a truncated integer value. Must cast the full expression, not just one operand.
Point 4 — Correct String construction and return: Uses string concatenation to build and return a String in the exact format "Change: X%".
Sample Solution:
public static String describeChange(double oldPrice, double newPrice)
{
double change = (newPrice - oldPrice) / oldPrice * 100;
int truncated = (int) change;
return "Change: " + truncated + "%";
}
For oldPrice = 80.0 and newPrice = 95.0: change = (95.0 − 80.0) / 80.0 × 100 = 18.75. Casting to int truncates to 18. The method returns "Change: 18%".SUMMARY
Variables and Data Types — Summary
Summary
Java's type system divides all data into two fundamental categories. Primitive types (int, double, and boolean for the AP exam) store values directly on the stack and are compared using ==. Reference types (such as String and all class types) store memory addresses that point to objects on the heap and should be compared using the .equals() method for content equality.
Every variable must be declared with a type before use, and Java's static typing catches type mismatches at compile time. Integer division truncates toward zero when both operands are int, widening conversions happen automatically (int → double), and narrowing casts require explicit syntax and truncate the fractional part. These principles underpin every subsequent topic in AP Computer Science A, from method calls and parameter passing to arrays, ArrayLists, and inheritance.