Now readingIntroduction
0%
AP Computer Science A · Framework 2026-27
Unit 1

Using Objects and Methods

Java programs build results by evaluating typed expressions, updating variables, and calling methods on classes and objects.

Exam weight
15–25%
Topics
15

Introduction

Java programs build results by evaluating typed expressions, updating variables, and calling methods on classes and objects.

This unit establishes the execution model used everywhere else in the course. Trace one statement at a time: evaluate inputs, identify the result type, update state, and record output. Keep primitive values separate from references, and keep references separate from the objects they identify.

01
Program pipeline

algorithm → source → compilation → execution

02
Typed state

variables, expressions, assignment, casts, and input

03
Method contracts

signatures, arguments, return values, and APIs

04
Object model

identity, construction, aliases, instance methods, and immutable strings

Java patterns and contracts

Use each pattern only after checking its type, range, and object-state conditions.

Current exam guidance: Aligned to the current 2026–27 AP Computer Science A framework and Java Quick Reference. The May 2027 digital exam has 42 multiple-choice questions in 90 minutes and four free-response questions in 90 minutes.
1.1

Introduction to Algorithms, Programming, and Compilers

How does a Java algorithm become a running program?

Short answer

A programmer expresses an algorithm as source code; the compiler checks and translates it, and the runtime executes the resulting bytecode.

Know firstOrdered steps · Inputs and outputs

Separate the plan, the source, and the run

An algorithm is a finite sequence of precise steps. Java source code is one way to express those steps so a computer can execute them. Before execution, javac checks syntax and type rules and translates a class into Java bytecode. The Java Virtual Machine then loads that bytecode and carries out the instructions.

The stage of failure matters. A missing semicolon is caught during compilation. Dividing an integer by zero compiles but throws an exception while the program runs. A program can also run without crashing and still produce the wrong answer; that is a logic error, so a clean compilation is only the first check.

Java trace

Follow one program through the pipeline

public class PipelineDemo {
  public static void main(String[] args) {
    int total = 3 + 4;
    System.out.println(total);
  }
}
Execution stateStep 1 of 4
stage
source
artifact
PipelineDemo.java
result
Java statements are readable text
Open complete trace table
Complete trace states
Stepstageartifactresult
1sourcePipelineDemo.javaJava statements are readable text
2compilePipelineDemo.classsyntax and types accepted
3runJVM statetotal becomes 7
4outputstandard output7
Output
7

The compiler accepts the declaration and addition. During execution, total stores 7 before println sends 7 to standard output.

Diagnose the stage first

  1. If compilation fails, inspect syntax, names, and types.
  2. If execution stops, identify the exception and the state that caused it.
  3. If output is wrong, trace variable values against the intended algorithm.

Keep these three ideas

  • Algorithms state the steps; programs encode them.
  • Compilation checks and translates source code.
  • Logic errors can survive compilation and execution.
1.2

Variables and Data Types

What does a declared Java variable promise about its values?

Short answer

A declaration gives a variable a name and a type, which limits the values and operations Java permits for that storage location.

Know firstLiteral values · Assignment notation

A type is an enforceable contract

The primitive types assessed here are int, double, and boolean. An int stores a whole number in a fixed 32-bit signed range, a double stores a finite-precision approximation to a real number, and a boolean stores only true or false. A declaration such as int count; creates a typed local name, but the local variable must receive a value before it is read.

Reference variables follow a different model: they can identify an object or hold null. The reference is not the object itself. Assignment must still be type-compatible, so Java rejects int count = 2.5; rather than silently discarding the fractional part.

Java trace

Track three primitive values

int count = 4;
double mean = 18.5;
boolean ready = count > 5;
System.out.println(count + "|" + mean + "|" + ready);
Execution stateStep 1 of 4
statement
int count = 4
count
4
mean
not declared
ready
not declared
Open complete trace table
Complete trace states
Stepstatementcountmeanready
1int count = 44not declarednot declared
2double mean = 18.5418.5not declared
3ready = count > 5418.5false
4println418.5false
Output
4|18.5|false

The comparison uses count 4, so four greater than five evaluates to false. The three stored values are then joined into one output line.

Read a declaration in three parts

  1. Identify the declared type.
  2. Identify the variable name.
  3. Evaluate the initializer, then confirm its result is assignment-compatible with the type.

Keep these three ideas

  • A type restricts values and operations.
  • Local variables must be assigned before use.
  • A reference identifies an object or holds null.
1.3

Expressions and Output

How do types and operator order determine a Java expression?

Short answer

Java evaluates operators by precedence and associativity, while operand types determine whether arithmetic is integral, floating-point, or string concatenation.

Know firstPrimitive types · Arithmetic order of operations

Evaluate before you print

In +, -, *, /, and % expressions involving only integers, Java performs integer arithmetic. Thus 7 / 2 is 3, not 3.5, because the fractional part is discarded. For the nonnegative operands used on the AP Exam, % returns the remainder: 7 % 2 is 1. If either operand is a double, numeric promotion makes the result a double.

Parentheses override normal precedence. The + operator also concatenates when either operand at that step is a string, and equal-precedence operations proceed left to right. print leaves the cursor on the same output line; println ends the line after printing. These output calls display a value but do not change the value of the expression.

Java trace

Compare division and concatenation

System.out.println(7 / 2);
System.out.println(7.0 / 2);
System.out.println("left=" + 7 + 2);
System.out.println("left=" + (7 + 2));
Execution stateStep 1 of 4
expression
7 / 2
operandType
int
value
3
Open complete trace table
Complete trace states
StepexpressionoperandTypevaluegrouping
17 / 2int3—
27.0 / 2double and int3.5—
3"left=" + 7 + 2—left=72("left=" + 7) + 2
4"left=" + (7 + 2)—left=9string + numeric sum
Output
3
3.5
left=72
left=9

Integer division yields 3, decimal division yields 3.5, and parentheses decide whether 7 plus 2 happens before string concatenation.

Trace an expression without guessing

  1. Apply parentheses first.
  2. Use precedence to find the next operation.
  3. Determine the operand types at that exact step.
  4. Record the result and type before continuing.

Keep these three ideas

  • Integer division discards the fractional part.
  • A double operand triggers floating-point arithmetic.
  • String concatenation follows the actual evaluation order.
1.4

Assignment Statements and Input

How do assignment and input change program state?

Short answer

Assignment evaluates the right side using the old state and stores that result on the left; input supplies values from outside the program that must be interpreted before use.

Know firstVariables and types · Method calls

Assignment replaces a stored value

In count = count + 1;, Java first reads the old count, adds one, and then stores the result back into count. The equals sign is not an algebraic claim that both sides stay equal. The left side must name a writable variable, field, or array location; an expression such as count + 1 cannot appear there.

Input may arrive as text, sound, touch, or another signal. Once a value has been supplied, assignment stores it under the same type-compatibility rules as any other expression. The AP Exam can ask what input means in an algorithm, but it does not assess a particular keyboard-input API; file-oriented Scanner methods are introduced later in Topic 4.6.

Java trace

Store a supplied input value, then update it

int suppliedValue = 7;
int count = suppliedValue;
count = count + 1;
System.out.println(suppliedValue + "|" + count);
Execution stateStep 1 of 4
action
receive supplied value
suppliedValue
7
Open complete trace table
Complete trace states
StepactionsuppliedValuecountoldCountnewCount
1receive supplied value7———
2count = suppliedValue77——
3count = count + 1——78
4println78——
Output
7|8

The supplied value remains seven. Assignment copies it into count, then a later assignment replaces count with eight.

Trace an assignment precisely

  1. Identify the value and type supplied to the program.
  2. Evaluate the entire right-side expression from the current state.
  3. Check that the result is compatible with the left-side variable.
  4. Replace only the left-side stored value.

Keep these three ideas

  • The right side is evaluated before storage.
  • Primitive assignment copies a value.
  • Input introduces a value from outside the running algorithm.
1.5

Casting and Range of Variables

What information can a cast change or lose?

Short answer

A cast explicitly converts a value to another type; narrowing can discard information, and fixed-width integer arithmetic can overflow.

Know firstInteger and double expressions · Assignment compatibility

Conversion happens at a specific point

Casting a double to int truncates toward zero: (int) 6.9 is 6, and (int) -6.9 is -6. It does not round to the nearest whole number. Placement matters: (double) (7 / 2) becomes 3.0 because integer division already happened, while (double) 7 / 2 becomes 3.5.

To round a nonnegative double x to its nearest integer with a cast, use (int) (x + 0.5); for a negative value, use (int) (x - 0.5). An int ranges from −231-2^{31} through 231−12^{31}-1, and arithmetic outside that range overflows into another permitted int value. A double also has finite precision, so a computed decimal can contain round-off error even when its mathematical result is exact.

Java trace

Apply sign-aware rounding and observe overflow

double positive = 4.6;
double negative = -4.6;
int roundedUp = (int) (positive + 0.5);
int roundedDown = (int) (negative - 0.5);
int wrapped = Integer.MAX_VALUE + 1;
System.out.println(roundedUp + "|" + roundedDown + "|" + wrapped);
Execution stateStep 1 of 5
operation
(int) (4.6 + 0.5)
valueBeforeCast
5.1
storedInt
5
Open complete trace table
Complete trace states
StepoperationvalueBeforeCaststoredIntvaluemathematicalValueresult
1(int) (4.6 + 0.5)5.15———
2(int) (-4.6 - 0.5)-5.1-5———
3Integer.MAX_VALUE——2147483647——
4+ 1 in int arithmetic—-2147483648—2147483648—
5println————5|-5|-2147483648
Output
5|-5|-2147483648

Adding or subtracting one half before truncation rounds 4.6 to five and negative 4.6 to negative five. Adding one to the largest int wraps to the smallest int.

Audit the conversion point

  1. Evaluate parentheses before applying a cast outside them.
  2. For plain double-to-int conversion, truncate toward zero.
  3. For nearest-integer rounding, choose the positive or negative half-offset recipe.
  4. Check int range and possible double round-off separately.

Keep these three ideas

  • A plain narrowing cast truncates toward zero.
  • Rounding uses a sign-aware half offset before the cast.
  • Finite int range and double precision can both change a mathematical result.
1.6

Compound Assignment Operators

What sequence is hidden inside a compound assignment?

Short answer

A compound assignment reads the current left-side value, applies an operator with the right side, converts as required, and stores the result back.

Know firstAssignment statements · Arithmetic types

Read, operate, then store

x += y is closely related to x = x + y, but the left side is evaluated only once and Java includes an implicit conversion back to the left-side type. The same pattern applies to -=, *=, /=, and %=. Increment and decrement, x++ and x--, change a numeric variable by exactly one.

For AP-level traces, treat x++ and x-- as complete standalone statements that update state. Prefix forms such as ++x, and increment or decrement embedded inside a larger expression, are outside the assessed course scope. Write the old value, apply the operation, then replace only the target.

Java trace

Update integer and decimal state

int items = 8;
items /= 3;
items++;
double scale = 5.0;
scale /= 2;
System.out.println(items + "|" + scale);
Execution stateStep 1 of 4
statement
items /= 3
before
8
operation
integer 8 / 3
after
2
Open complete trace table
Complete trace states
Stepstatementbeforeoperationafterresult
1items /= 38integer 8 / 32—
2items++2—3—
3scale /= 25double 5.0 / 22.5—
4println———3|2.5
Output
3|2.5

Integer compound division stores two, the standalone postfix increment changes it to three, and double compound division stores 2.5.

Expand the state change mentally

  1. Record the target's old value and type.
  2. Evaluate the operator using the operand types.
  3. Apply the compound-assignment conversion.
  4. Store the new value and continue from that state.

Keep these three ideas

  • Compound assignment reads, operates, and stores.
  • The target type still controls the stored value.
  • Postfix increment and decrement are assessed as standalone updates.
1.7

Application Program Interface (API) and Libraries

How does an API let code use behavior without knowing its implementation?

Short answer

An API publishes method contracts—names, parameters, return types, and behavior—so callers can use a library through its documented interface.

Know firstTypes · Method-call syntax

A contract is enough to make a correct call

A library groups reusable classes into packages. A class defines a reference type whose attributes store data and whose methods define behavior. Its API tells a caller which operations are available and what each operation expects and returns. For String, substring(int beginIndex, int endIndex) needs two integer arguments, returns a String, includes the begin index, and excludes the end index.

The AP Java Quick Reference defines the library surface students may be expected to recognize without extra documentation. Memorizing an implementation is unnecessary; reading the contract is essential. Preconditions such as valid indices remain the caller's responsibility and can cause runtime exceptions when violated.

Java trace

Apply three String contracts

String word = "cedar";
int size = word.length();
int firstE = word.indexOf("e");
String tail = word.substring(1, 4);
System.out.println(size + "|" + firstE + "|" + tail);
Execution stateStep 1 of 4
call
word.length()
receiver
cedar
result
5
Open complete trace table
Complete trace states
StepcallreceiverresultselectedIndices
1word.length()cedar5—
2word.indexOf("e")cedar1—
3word.substring(1, 4)—eda1, 2, 3
4println—5|1|eda—
Output
5|1|eda

Length counts five characters, indexOf finds e at zero-based index one, and substring selects indices one through three.

Audit a library call

  1. Identify the receiver class or class name.
  2. Match the argument count and types to a documented signature.
  3. Check the method's preconditions.
  4. Use the return type to decide how the result can be stored or combined.

Keep these three ideas

  • An API exposes behavior through contracts.
  • Signatures specify call shape and return type.
  • Callers must honor documented preconditions.
1.8

Documentation with Comments

Which information belongs in a useful program comment?

Short answer

Useful comments explain purpose, contracts, assumptions, and non-obvious choices that the executable code cannot express clearly on its own.

Know firstMethods · Program behavior

Document intent, not punctuation

Java supports end-of-line comments beginning with //, block comments enclosed by /* and */, and documentation comments beginning with /**. A comment is ignored during execution, so it cannot repair incorrect code. Strong documentation explains why a method exists, what inputs it expects, what result it guarantees, and whether it changes object state.

Documentation must remain synchronized with behavior. A stale claim is worse than silence because a caller may rely on it. Preconditions define what the caller must provide; postconditions describe what is true after a successful call. Those statements also suggest focused tests at ordinary and boundary values.

Java trace

Compare the contract with the execution

/** Returns value limited to the inclusive interval [0, 100]. */
static int clamp(int value) {
  if (value < 0) return 0;
  if (value > 100) return 100;
  return value;
}
System.out.println(clamp(-8) + "|" + clamp(40) + "|" + clamp(130));
Execution stateStep 1 of 4
input
-8
branch
value < 0
returned
0
Open complete trace table
Complete trace states
StepinputbranchreturnedcontractCheckresult
1-8value < 00——
240neither boundary branch40——
3130value > 100100——
4———all results in [0, 100]true
Output
0|40|100

The three calls exercise the lower boundary, interior, and upper boundary behavior promised by the method comment.

Write a contract that can be checked

  1. State the method's purpose in one sentence.
  2. Name meaningful preconditions and side effects.
  3. Describe the return or postcondition without restating each source line.
  4. Compare the comment with boundary behavior whenever the code changes.

Keep these three ideas

  • Comments communicate intent and contracts.
  • Executable code determines behavior.
  • Documentation must agree with boundary cases.
1.9

Method Signatures

How does Java decide which method a call means?

Short answer

Java matches the method name and ordered parameter types to an applicable signature, then uses the declared return type to type the result.

Know firstTypes · API contracts

Parameters distinguish overloaded methods

A method declaration includes a name, parameter list, return type, and body. For overloading, methods in one class must differ in their parameter lists; changing only the return type is not enough. At a call site, the compiler uses the supplied argument types and permitted conversions to choose an applicable overload.

Parameters are local names that receive copies of argument values when a call begins. The return type states what value comes back, or void when no value is returned. A caller must use the result in a type-compatible context and cannot use a void call as a value.

Java trace

Resolve two overloaded calls

static int combine(int a, int b) { return a + b; }
static String combine(String a, String b) { return a + "-" + b; }
System.out.println(combine(3, 4));
System.out.println(combine("up", "hill"));
Execution stateStep 1 of 4
call
combine(3, 4)
argumentTypes
int, int
selectedSignature
combine(int, int)
result
7
Open complete trace table
Complete trace states
StepcallargumentTypesselectedSignatureresultoutputLinevalue
1combine(3, 4)int, intcombine(int, int)7——
2combine("up", "hill")String, Stringcombine(String, String)up-hill——
3————17
4————2up-hill
Output
7
up-hill

The integer arguments select the integer overload. The two String arguments select the String overload.

Match a call to a declaration

  1. Write the call's method name.
  2. Determine each argument type in order.
  3. Find an applicable parameter list.
  4. Use the selected declaration's return type and behavior.

Keep these three ideas

  • Parameter lists distinguish overloads.
  • Arguments initialize parameter variables.
  • The selected declaration determines the return type.
1.10

Calling Class Methods

What happens when a program calls a static method?

Short answer

A class-method call evaluates its arguments, initializes a new set of parameter variables, executes the method body, and substitutes the returned value.

Know firstMethod signatures · Expression evaluation

Each call gets its own local state

A static method belongs to a class rather than to one particular instance. It is commonly called with ClassName.method(arguments), although a call inside the same class may omit the class name. Java evaluates arguments before control enters the method, so nested calls finish from the inside outward.

Parameters and local variables exist only for that invocation. Returning a value ends the call and passes one result to the surrounding expression. Changing a primitive parameter does not change the caller's primitive variable because the parameter received a copy.

Java trace

Unwind nested class-method calls

static int twice(int value) { return value * 2; }
static int shift(int value) { return value + 3; }
int result = twice(shift(5));
System.out.println(result);
Execution stateStep 1 of 4
action
evaluate inner call
call
shift(5)
parameterValue
5
returned
8
Open complete trace table
Complete trace states
StepactioncallparameterValuereturnedexpressionresult
1evaluate inner callshift(5)58——
2substitute inner result———twice(8)—
3execute outer calltwice(8)816——
4assign and print————16
Output
16

The inner shift call returns eight. That value becomes the argument to twice, which returns sixteen.

Trace calls from the innermost expression

  1. Evaluate argument expressions left to right.
  2. Create parameter values for the selected method.
  3. Trace its local statements until return.
  4. Replace the call expression with the returned value.

Keep these three ideas

  • Static methods are associated with a class.
  • Arguments are evaluated before the body runs.
  • A returned value replaces the call expression.
1.11

Math Class

Which mathematical operations does the Math class provide, and what ranges do they return?

Short answer

Math supplies static numerical methods; correct use depends on each signature, return type, and range contract.

Know firstClass-method calls · Casting and numeric types

Treat each Math method as a precise contract

The Math class belongs to java.lang, which is available without an import, and contains only class methods. The AP Java Quick Reference includes Math.abs for int and double values, Math.pow, and Math.sqrt. Each returns the type described by its signature. Math.random() returns a double in the half-open interval [0.0,1.0)[0.0, 1.0).

For (int)(Math.random() * 6) + 1, multiplication gives a value from 0.0 up to but not including 6.0, the cast yields 0 through 5, and adding one yields 1 through 6. Parentheses are critical: casting before multiplication would turn every random value into zero.

Java trace

Verify range and root contracts without randomness in the output

double r = Math.random();
int die = (int) (r * 6) + 1;
boolean rangeOk = die >= 1 && die <= 6;
boolean rootOk = Math.sqrt(81) == 9.0;
if (rangeOk && rootOk) {
  System.out.println("range-ok|root-ok");
} else {
  System.out.println("bad");
}
Execution stateStep 1 of 4
expression
Math.random()
lowerBound
0.0 inclusive
upperBound
1.0 exclusive
Open complete trace table
Complete trace states
StepexpressionlowerBoundupperBoundpossibleIntegersrangeOkvaluerootOk
1Math.random()0.0 inclusive1.0 exclusive————
2(int)(r * 6)——0 through 5———
3die——1 through 6true——
4Math.sqrt(81)————9true
Output
range-ok|root-ok

Any permitted random result maps to an integer from one through six. The square root method returns nine for eighty-one.

Derive a random integer range

  1. Start with the half-open interval returned by Math.random.
  2. Multiply both interval endpoints by the number of outcomes.
  3. Apply the int cast to find the integer range.
  4. Add the desired lower bound and verify both endpoints.

Keep these three ideas

  • Math methods are static class methods.
  • Math.random returns a half-open interval.
  • Scale, cast, and offset determine an integer range.
1.12

Objects: Instances of Classes

How are an object, its class, and a reference related?

Short answer

A class defines a type and its behavior; an object is one runtime instance with its own state, and a reference is a value that can identify that object.

Know firstClasses and methods · Variable state

Identity and state answer different questions

A class is a blueprint for the attributes and behaviors of its instances. Related classes may share inherited behavior through a superclass, and every Java class is directly or indirectly a subclass of Object. You need to recognize that hierarchy and its shared guarantees; designing or implementing inheritance relationships is outside this AP course.

A reference variable stores access to an object, not the object inside the variable. Two variables can therefore refer to the same instance. A mutation through either alias becomes visible through the other because only one object changed. Reassigning a reference changes which object that variable identifies; it does not move or duplicate an object.

Java trace

Observe one object through two references

Counter first = new Counter(3);
Counter second = first;
second.add(1);
System.out.println(first.read() + "|" + second.read());
Execution stateStep 1 of 4
statement
new Counter(3)
objectState
value 3
first
object A
Open complete trace table
Complete trace states
StepstatementobjectStatefirstsecondaliasesfirstReadsecondRead
1new Counter(3)value 3object A————
2second = first—object Aobject A———
3second.add(1)value 4——first and second——
4println————44
Output
4|4

Both references identify one Counter object. Adding through second changes that object, so both read calls return four.

Draw references separately from objects

  1. Create one box for each reference variable.
  2. Create a separate state record for each new object.
  3. Draw an arrow from each non-null reference to its object.
  4. Apply an instance method to the receiver object, then update every view of that object.

Keep these three ideas

  • A class defines a type; an object is an instance.
  • References and objects occupy different parts of the state model.
  • Aliases expose mutations to the same object.
1.13

Object Creation and Storage (Instantiation)

What exactly changes when `new` creates an object?

Short answer

new selects the constructor whose signature matches the arguments, initializes a distinct object, and produces a reference that can be stored or passed.

Know firstObjects and references · Constructor-call syntax

One constructor call creates one identity

A constructor signature consists of the class name and ordered parameter types. Overloaded constructors share the class name but have different signatures, so new Box(4) selects Box(int) while new Box(3, 4) selects Box(int, int). Arguments must match in number, order, and compatible type.

Assignment can copy a reference without constructing anything. If Box b = a;, both variables identify the existing object. If b = new Box(12);, only b is rebound to the new object; a still identifies the first one. An object with no reachable reference becomes eligible for garbage collection, though collection timing is not part of a trace.

Java trace

Select overloads and distinguish an alias

Box first = new Box(4);
Box alias = first;
Box area = new Box(3, 4);
System.out.println(first.value() + "|" + (first == alias) + "|" + area.value());
Execution stateStep 1 of 4
statement
new Box(4)
selectedSignature
Box(int)
first
object A
objectAValue
4
Open complete trace table
Complete trace states
StepstatementselectedSignaturefirstobjectAValuealiasareaobjectBValuefirstValuealiasMatchesareaValue
1new Box(4)Box(int)object A4——————
2alias = first—object A—object A—————
3new Box(3, 4)Box(int, int)———object B12———
4println——————4true12
Output
4|true|12

One integer selects the one-parameter constructor and stores four. Two integers select the two-parameter constructor and store their product twelve. Reference assignment makes alias identify the first object.

Count objects and references independently

  1. List each available constructor signature.
  2. Match the call’s argument count, order, and types.
  3. Create an object record only for a new expression.
  4. Copy argument values into parameters and run that constructor.
  5. Store the returned reference; ordinary assignment only copies that reference.

Keep these three ideas

  • Argument types select an overloaded constructor signature.
  • Each new expression creates a distinct identity.
  • Assignment can create an alias without constructing an object.
1.14

Calling Instance Methods

How does the receiver affect an instance-method call?

Short answer

The reference before the dot selects the receiver object, whose state the method can read or modify while its arguments initialize separate parameters.

Know firstObject references · Method calls

The receiver is an implicit input

In meter.add(3), Java evaluates meter to find the receiver, evaluates the argument 3, and invokes add with access to that object's fields. Calls on two different receiver objects execute the same method code against different state. A method can return a value, mutate the receiver, do both, or do neither according to its contract.

Calling an instance method through null throws NullPointerException because there is no receiver object. The error is not caused by the method body; execution cannot begin on a missing object. Trace receiver identity before entering the method, especially when aliases or reassignments appear.

Java trace

Send calls to two independent receivers

Meter left = new Meter(5);
Meter right = new Meter(20);
left.add(3);
System.out.println(left.read() + "|" + right.read());
Execution stateStep 1 of 4
statement
new Meter(5)
left
object L
leftState
5
Open complete trace table
Complete trace states
StepstatementleftleftStaterightrightStatereceiverleftReadrightRead
1new Meter(5)object L5—————
2new Meter(20)——object R20———
3left.add(3)—8—20object L——
4println—————820
Output
8|20

The add call uses object L as its receiver and changes only its state. Object R remains at twenty.

Trace a receiver call

  1. Evaluate the reference before the dot.
  2. Stop with a runtime error if that reference is null.
  3. Evaluate arguments and initialize parameters.
  4. Run the method against the selected object's fields.
  5. Record any returned value and persistent state change.

Keep these three ideas

  • The receiver selects an object.
  • Arguments and receiver state play different roles.
  • Calling through null fails before the body runs.
1.15

String Manipulation

How do zero-based indices and immutability shape String operations?

Short answer

A String is an immutable sequence indexed from zero; methods inspect it or return new strings while the original object remains unchanged.

Know firstString API · Object references

Indices mark positions and boundaries

A String can be created from a literal or with the String constructor. The class belongs to java.lang, so no import is required. For a string of length nn, character positions run from 0 through n−1n-1. substring(begin, end) includes begin and excludes end; substring(index, index + 1) produces the one-character String at a valid index. indexOf returns the first matching index or -1 when no match exists.

Strings are immutable: substring and concatenation return new values rather than editing the receiver. equals tests String content, while compareTo returns a negative, zero, or positive result according to alphabetical order. Concatenating any object with a String implicitly uses that object’s inherited toString representation; writing a custom override is outside this course.

Java trace

Slice, search, order, and reassign

String word = "moss";
String tail = word.substring(1, 4);
String letter = word.substring(1, 2);
int where = word.indexOf("ss");
boolean before = word.compareTo("most") < 0;
word += "y";
System.out.println(tail + "|" + letter + "|" + where + "|" + before + "|" + word);
Execution stateStep 1 of 5
operation
substring(1, 4)
selectedIndices
1, 2, 3
result
oss
original
moss
Open complete trace table
Complete trace states
StepoperationselectedIndicesresultoriginalselectedIndexfirstMatchIndexfirstDifferentCharactersoldStringnewValue
1substring(1, 4)1, 2, 3ossmoss—————
2substring(1, 2)—o—1————
3indexOf("ss")————2———
4compareTo("most") < 0—true———s and t——
5word += "y"——————mossmossy
Output
oss|o|2|true|mossy

The longer slice is oss, the single-position slice is o, ss begins at index two, moss sorts before most, and concatenation reassigns word to mossy.

Mark string boundaries before calling

  1. Write each character with its zero-based index.
  2. For substring, mark an included start and excluded end boundary.
  3. For indexOf, return the first start index or -1.
  4. Interpret only the sign of compareTo unless an exact value is requested.
  5. Store a returned String when the variable should change.

Keep these three ideas

  • String indices begin at zero; substring includes its start and excludes its end.
  • equals compares content, while compareTo reports ordering.
  • String operations return values without mutating the receiver.

Using objects and methods review

Trace short Java programs without blending compilation, expression evaluation, reference identity, and output.

State and types

  • Identify each variable's declared type and current value.
  • Evaluate integer arithmetic before widening the result.
  • Place casts at the operation whose behavior must change.

Calls and objects

  • Match actual arguments to a method signature.
  • Separate a reference variable from the object it identifies.
  • Treat String operations as producing new values rather than changing the original string.

Debugging

  • Classify errors as compile-time, runtime, or logical.
  • Check index and substring bounds before a call.
  • Record output only when the print statement executes.

Practice AP Computer Science A in the real test engine.

Free practice set: timed, the same engine as our full-length tests, every answer explained.