AP Computer Science A — Using Objects and Methods (Deep Study Notes)

Objects, Classes, and the Java API

What an object is (and why Java cares so much)

An object is a bundled package of data and behavior. The data an object “remembers” is called its state (for example, the characters inside a String, or the current position inside a Scanner as it reads input). The behavior an object can perform is expressed through methods (for example, length() for a String, or nextInt() for a Scanner).

Java is an object-oriented language, which means that most useful work is done by creating objects and asking them to do things by calling methods. This matters because AP Computer Science A questions often give you code using objects you didn’t write (from the Java library) and expect you to predict what it does or write a few lines that use those objects correctly.

A helpful analogy: a class is like a blueprint for a type of device, and an object is an actual device built from that blueprint. Two phones can be the same model (same class) but have different battery levels and open apps (different state).

Classes: the “type” of an object

A class defines what state and methods objects of that class will have. When you declare a variable of a class type, you are saying, “This variable can refer to an object built from this class.”

For example, String is a class in the Java standard library. Any particular piece of text (like "hello") is a String object.

The Java API and why you should treat it like a menu

The Java API (Application Programming Interface) is the collection of prewritten classes and methods Java provides. In AP CSA, you’re expected to use parts of this API—especially String, the wrapper classes (Integer, Double, etc.), and Math.

On many AP questions, you don’t need to memorize every method—what you need is the ability to:

  • Recognize the difference between instance methods (called on an object, like str.length()) and static methods (called on a class, like Math.sqrt(9))
  • Use method signatures correctly: name, parameters, and return type
  • Reason about what a method call evaluates to

Reference types: variables don’t “hold the object”

In Java, class types like String are reference types. A variable of a reference type does not store the object’s contents directly. Instead, it stores a reference to an object somewhere in memory.

This matters because:

  • Two variables can refer to the same object (aliasing)
  • A reference variable can be null (meaning it refers to no object)
  • Using a null reference like an object causes a NullPointerException

Example idea (not code yet): if a and b refer to the same String object, then calling methods on either one is “using” the same underlying object.

null and NullPointerException

The literal null represents “no object.” You can assign null to any reference variable:

String s = null;

But you cannot call methods on null:

System.out.println(s.length()); // NullPointerException

A common beginner misconception is thinking null is an “empty string.” It is not. An empty string is a real String object with length 0:

String empty = "";
System.out.println(empty.length()); // prints 0
Exam Focus
  • Typical question patterns:
    • You’re given code with object variables and method calls and must determine the output.
    • You choose the correct method call based on a class’s behavior (often String or Math).
    • You identify what causes a runtime error (especially NullPointerException).
  • Common mistakes:
    • Treating a reference variable as if it stores the object itself (confusing assignment/aliasing).
    • Thinking null is the same as "".
    • Calling a method on a variable that might be null.

Constructing Objects with Constructors

Creating an object: the role of new

To get an actual object, you usually use the keyword new. This allocates a new object in memory and returns a reference to it.

The general pattern looks like:

ClassName variableName = new ClassName(arguments);

The part that looks like a method call after new is a constructor.

Constructors: special “setup” code

A constructor is special code that runs when an object is created. Constructors:

  • Have the same name as the class
  • Do not have a return type (not even void)
  • Can take parameters to initialize the object

Many classes provide multiple constructors with different parameter lists. This is called overloading.

For example, String has multiple ways to construct strings, but in AP CSA you most commonly see string literals like "AP" rather than explicit new String("AP").

Storing the reference in a variable

When you write:

String name = "Ada";

Java creates a String object (behind the scenes) and stores a reference to it in name. The variable name is not the characters themselves—it is a way to access the String object.

Aliasing: two variables, one object

Because variables store references, this can happen:

String a = "hello";
String b = a;

Now a and b refer to the same String object. With String specifically, you can’t change the object anyway (strings are immutable—more on that later), but aliasing becomes very important with mutable objects in later units.

Even in Unit 1, aliasing shows up conceptually: assignment between reference variables does not copy an object; it copies the reference.

A common library object: Scanner

Scanner is a Java library class used to read input. It’s not always heavily tested with interactive input on the AP multiple-choice section, but it’s a standard example of constructing and using an object.

import java.util.Scanner;

Scanner scan = new Scanner(System.in);
int x = scan.nextInt();

Here’s what’s happening step by step:

  1. new Scanner(System.in) constructs a Scanner object configured to read from standard input.
  2. The reference is stored in scan.
  3. scan.nextInt() calls an instance method that returns an int.

If you ever see Scanner in a question, pay attention to the method return types: nextInt() returns an int, nextDouble() returns a double, and nextLine() returns a String.

When you don’t see new

Some objects appear without new in your code, for example System.out. System is a class, and out is a preexisting object (a static field) that you can call methods on, such as println.

So this:

System.out.println("Hi");

is still “calling a method on an object.” You just didn’t construct that object yourself.

Exam Focus
  • Typical question patterns:
    • Write one line of code that constructs an object with the correct constructor and stores it in a variable.
    • Identify what object is created and what the variable stores (object vs reference).
    • Trace code where reference variables are assigned to each other.
  • Common mistakes:
    • Forgetting new when creating an object (writing Scanner s = Scanner(System.in);).
    • Confusing constructors with methods (trying to use a return value from a constructor).
    • Thinking ClassName x = y; makes a copy of the object rather than copying the reference.

Calling Methods: Void vs Non-void, Parameters, and Return Values

The dot operator: “ask this object to do something”

Most object interaction in Java uses the dot operator .:

objectReference.methodName(arguments)

This means: find the object referred to by objectReference, then run methodName on it.

Java chooses which method to run based on:

  • The class of the object
  • The method name
  • The number and types of arguments (the method signature)

Parameters vs arguments

These two words are easy to mix up:

  • Parameters are the variables in a method or constructor definition.
  • Arguments are the actual values you pass in when you call it.

If a method is described as substring(int beginIndex, int endIndex), then beginIndex and endIndex are parameters. In s.substring(2, 5), the arguments are 2 and 5.

This matters on AP questions because they often test whether you know what type an argument must be (for example, that substring needs integer indices).

Void methods vs non-void methods

A method can either:

  • Perform an action without giving a value back (void method)
  • Produce a value (non-void method, also called a “returning” method)

Void method example:

System.out.println("Hello");

println prints as a side effect; it does not evaluate to a value you can store.

Non-void method example:

String s = "hello";
int n = s.length();

length() returns an int. That returned value can be stored, used in an expression, compared, etc.

A key rule: you can only assign a method call to a variable if the method returns a compatible type.

Using return values in expressions

Because non-void methods evaluate to a value, you can use them inside larger expressions:

String s = "computer";
int lastIndex = s.length() - 1; // length() gives an int

This kind of expression nesting is extremely common on AP CSA.

Method chaining

Sometimes a method returns an object, and you call another method on the returned object. This is called method chaining.

For example:

String result = "hello".toUpperCase().substring(1);

To understand this, you read it left to right:

  1. "hello".toUpperCase() returns the string "HELLO".
  2. On that returned string, .substring(1) returns "ELLO".

Chaining is especially common with String methods.

A common mistake is assuming intermediate method calls “change” the original object. With String, they don’t—each call returns a new String.

Static methods: calling a method on a class

Some methods belong to a class itself rather than to an instance. These are static methods.

The Math class is the main example in this unit:

double r = Math.sqrt(16);

Notice there is no new Math() and no object variable. You call sqrt directly on the class name.

Students often try to write Math m = new Math();—that’s not how Math is designed.

Return type awareness: the skill AP loves to test

Many AP questions boil down to: “What is the type/value of this expression?” If you know method return types, you can reason correctly.

For example:

  • s.length() is an int
  • s.substring(1, 3) is a String
  • Math.random() is a double
Exam Focus
  • Typical question patterns:
    • Determine the value (or type) of an expression containing method calls.
    • Pick the correct line of code that uses a method’s return value properly.
    • Trace method chaining and identify intermediate results.
  • Common mistakes:
    • Treating a void method as if it returns a value (trying to assign println).
    • Forgetting parentheses when calling a method (s.length instead of s.length()).
    • Mixing up instance vs static calls (writing s.sqrt(9) or Math m = new Math()).

The String Class: Text as Objects

Why String is central in Unit 1

Text shows up everywhere: user input, file contents, messages, names, and formatted output. Java represents text using the String class, which is one of the most frequently tested library classes on AP CSA.

When you work with String, you’re constantly using object methods—so it’s the perfect vehicle for learning how method calls, parameters, and return values work.

Strings are immutable

A crucial property: Strings are immutable, meaning once a String object is created, it cannot be changed.

So when you call a method like toUpperCase(), Java does not modify the existing string. Instead, it creates and returns a new String.

This matters because code like this does not do what beginners expect:

String s = "hi";
s.toUpperCase();
System.out.println(s); // still "hi"

You ignored the return value. To actually keep the uppercase version, you must assign it:

s = s.toUpperCase();

Indices: characters are numbered starting at 0

Many String methods use indices. In Java, indices start at 0, not 1.

For a string of length n, valid character indices go from 0 to n - 1.

If you use an index outside that range, you’ll get a StringIndexOutOfBoundsException at runtime.

Core String methods you must understand

Below are several String methods that frequently appear in AP CSA questions. The goal is not just memorizing names—it’s understanding what they return and how to interpret their parameters.

length()
  • Returns the number of characters in the string as an int.
String s = "AP CSA";
System.out.println(s.length()); // 6 (includes the space)
substring(...)

substring extracts part of a string and returns a new String.

Common forms:

  • substring(int beginIndex) returns from beginIndex to the end.
  • substring(int beginIndex, int endIndex) returns from beginIndex up to (but not including) endIndex.

That “endIndex is exclusive” rule is one of the most tested details.

Example:

String s = "computer";
System.out.println(s.substring(3));    // "puter"
System.out.println(s.substring(1, 4)); // "omp"

Why substring(1, 4) is "omp":

  • index 1: o
  • index 2: m
  • index 3: p
  • stop before index 4
indexOf(...)

indexOf searches for a substring (or character) and returns the index of the first occurrence.

  • If it’s not found, it returns -1.
String s = "banana";
System.out.println(s.indexOf("na")); // 2
System.out.println(s.indexOf("z"));  // -1

A common mistake is forgetting the -1 case. On AP questions, you often need to handle “not found” explicitly.

equals(...) vs ==

To compare the contents of strings, use equals:

String a = "hi";
String b = "hi";
System.out.println(a.equals(b)); // true

== compares whether two reference variables refer to the exact same object, not whether the text matches. Sometimes a == b will be true (due to string interning), sometimes not—so you should not rely on it.

This is a major AP CSA point: when comparing strings for equality, use equals.

compareTo(...)

compareTo compares strings in lexicographic (dictionary) order and returns an int:

  • Negative if the calling string comes before the argument
  • 0 if they are equal
  • Positive if it comes after

You do not need to memorize the exact positive/negative value—only the sign and what it means.

System.out.println("ant".compareTo("bat")); // negative
System.out.println("bat".compareTo("bat")); // 0
System.out.println("cat".compareTo("bat")); // positive
toLowerCase() and toUpperCase()

These return new strings with changed letter case.

String s = "Ap";
String t = s.toLowerCase();
System.out.println(s); // "Ap"
System.out.println(t); // "ap"

Again, immutability is the key idea: s doesn’t change unless you reassign it.

Example: extracting the last character

To get the last character as a one-character string:

String s = "Java";
String last = s.substring(s.length() - 1);
System.out.println(last); // "a"

What can go wrong?

  • If s is empty (""), then s.length() - 1 is -1, which is an invalid index.

Example: checking whether a string contains another string

You can use indexOf:

String s = "university";
boolean hasVers = s.indexOf("vers") >= 0;
System.out.println(hasVers); // true

This works because indexOf returns -1 when not found.

Exam Focus
  • Typical question patterns:
    • Predict the output of substring, indexOf, and chained String method calls.
    • Choose the correct code to compare strings (equals vs ==).
    • Determine what happens with boundary indices (0, length(), length() - 1).
  • Common mistakes:
    • Treating the second substring index as inclusive instead of exclusive.
    • Using == to compare string contents.
    • Off-by-one errors when using length() to compute indices.

Wrapper Classes and Autoboxing

Primitive types vs objects (the practical difference)

Java has primitive types (like int, double, boolean) and reference types (objects). Primitive values are not objects, so they don’t have methods.

But sometimes you need an object form of a primitive—for example:

  • Some library classes and data structures store objects, not primitives.
  • You may want to use useful static methods (like converting a numeric string to an integer).

That’s where wrapper classes come in.

What wrapper classes are

A wrapper class is a class that “wraps” a primitive value inside an object. Common wrappers in AP CSA:

  • Integer wraps int
  • Double wraps double
  • Boolean wraps boolean

You can create wrapper objects, but more often you’ll use their static methods.

Autoboxing and unboxing

Java can automatically convert between a primitive and its wrapper in many situations:

  • Autoboxing: primitive to wrapper
  • Unboxing: wrapper to primitive

Example:

Integer a = 7;     // autoboxing (int -> Integer)
int b = a;         // unboxing (Integer -> int)

This is convenient, but it can hide what’s actually happening, which can lead to subtle errors.

Useful Integer and Double methods

Parsing strings into numbers

A very common task is converting a numeric string to a number.

int x = Integer.parseInt("123");
double y = Double.parseDouble("3.14");

If the string isn’t a valid number format, these methods throw a NumberFormatException.

Converting numbers to strings

You’ll often see String.valueOf(...) (from the String class) or wrapper toString methods.

String s1 = String.valueOf(42);
String s2 = Integer.toString(42);

Comparing wrapper objects: don’t rely on ==

Just like with strings, == compares references for wrapper objects. Use equals to compare the wrapped values.

Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);      // not reliable to reason about
System.out.println(a.equals(b)); // true

Even though Java sometimes reuses certain Integer objects behind the scenes, AP-style reasoning should be: == is for primitive equality; equals is for object content equality.

A dangerous pitfall: unboxing null

If you have a wrapper variable that is null and Java tries to unbox it to a primitive, you will get a NullPointerException.

Integer n = null;
int x = n; // NullPointerException due to unboxing

This shows up in code-tracing questions where a wrapper might not have been initialized.

Exam Focus
  • Typical question patterns:
    • Convert between strings and numeric types using parseInt / parseDouble.
    • Identify the type/value produced by an expression involving wrappers and primitives.
    • Recognize when equals is needed for object comparisons.
  • Common mistakes:
    • Using == to compare wrapper objects.
    • Forgetting that parsing can throw an exception if the format is invalid.
    • Unboxing a null wrapper into a primitive.

The Math Class and Random Numbers

Why Math is different: static utility methods

The Math class provides common mathematical functions. Unlike String, you don’t create Math objects. You call methods directly on the class:

double a = Math.abs(-5.0);
double r = Math.sqrt(49);

These are static methods. The mental model is: Math is a toolbox; you don’t need to build a toolbox object to use a hammer.

Common Math methods in AP CSA

You should be comfortable recognizing what these do and what type they return.

  • Math.abs(x) returns the absolute value
  • Math.pow(a, b) returns a^b as a double
  • Math.sqrt(x) returns the square root as a double
  • Math.max(a, b) and Math.min(a, b) return the larger/smaller of two numbers

Be careful with return types: even when you pass integers to pow or sqrt, the result is a double.

Rounding and casting

Java has multiple rounding-related tools:

  • Casting (int) truncates toward 0 (it does not round).
  • Math.round(x) rounds to the nearest integer-like value, but returns long for double input.

Example showing truncation:

double x = 9.9;
int t = (int) x;
System.out.println(t); // 9

Students often think casting rounds; it doesn’t.

Math.random() and the idea of a range

Math.random() returns a double in the range:

  • Greater than or equal to 0.0
  • Less than 1.0

So it’s in [0.0, 1.0).

That matters because you can scale it to generate random numbers in other ranges.

Random integer from 0 to n-1

To get a random integer from 0 to n - 1:

r = (int)(Math.random() * n)

Explanation:

  1. Math.random() gives a double from 0.0 up to (but not including) 1.0.
  2. Multiplying by n gives a double from 0.0 up to (but not including) n.
  3. Casting to int truncates, producing one of 0, 1, 2, ..., n - 1.

Example:

int die = (int)(Math.random() * 6) + 1; // 1..6
System.out.println(die);

Notice the + 1 shifts the range.

Random integer from a to b (inclusive)

If you want a random integer between a and b, inclusive, with a <= b, the size of the range is b - a + 1. A common pattern is:

r = (int)(Math.random() * (b - a + 1)) + a

This pattern is frequently tested conceptually: AP questions may ask which expression correctly generates a number in a given range.

What can go wrong with random ranges

Typical bugs include:

  • Forgetting the + 1 when the upper bound should be inclusive
  • Putting the cast in the wrong place, like (int)Math.random() * n which becomes 0 * n most of the time because (int)Math.random() is always 0

Compare these:

(int)(Math.random() * 10)    // 0..9 (correct)
(int)Math.random() * 10      // always 0 (wrong)

The parentheses determine what gets truncated.

Exam Focus
  • Typical question patterns:
    • Identify the correct expression to generate a random integer in a specified range.
    • Trace code that mixes Math methods, casting, and integer division.
    • Determine output types (for example, that Math.sqrt(9) is double).
  • Common mistakes:
    • Casting too early in a Math.random() expression.
    • Confusing truncation with rounding.
    • Forgetting that many Math methods return double even with integer inputs.

Putting It Together: Reading, Tracing, and Writing Code with Objects

The core workflow: create (or receive) an object, then use methods

Most Unit 1 code fits a simple pattern:

  1. You have a reference to an object (maybe created with new, maybe provided like System.out)
  2. You call methods on it
  3. You use returned values to compute other results
  4. You store results in variables or print them

The AP exam frequently tests your ability to read these steps accurately—especially when method calls are nested.

Expression tracing with method calls

When tracing code, treat each method call as producing a value (for non-void methods) or producing a side effect (for void methods). A reliable approach is:

  • Evaluate inside parentheses first
  • Replace non-void method calls with their returned values
  • Keep track of variable updates (reassignment)
Worked tracing example (Strings + indices)

Consider:

String s = "mississippi";
int i = s.indexOf("iss");
String t = s.substring(i, i + 4);
System.out.println(t);

Step-by-step:

  • s is "mississippi"
  • s.indexOf("iss") finds the first occurrence of "iss"
    • In "mississippi", the first "iss" starts at index 1
    • So i becomes 1
  • s.substring(i, i + 4) becomes s.substring(1, 5)
    • That extracts indices 1, 2, 3, 4
    • Characters: i s s i
    • So t is "issi"
  • It prints issi

What can go wrong?

  • Miscounting indices (forgetting the string starts at 0)
  • Treating the substring end index as inclusive (it’s exclusive)

Writing small code snippets that use objects correctly

AP questions often ask you to write a few lines (not whole programs). When writing these snippets, focus on:

  • Correct method names and parentheses
  • Correct argument types and order
  • Correct use of return values
  • Correct variable types
Example: compute the initial of a first name

Task: Given String first, create a String initial containing the first letter (as a one-character string).

Reasoning:

  • The first character is at index 0.
  • To extract one character as a string, you can use substring(0, 1).
String initial = first.substring(0, 1);

Common error: using substring(0, 0) (that returns the empty string).

Example: safely checking for a substring

Suppose you want to check whether word contains "cat".

boolean containsCat = word.indexOf("cat") != -1;

This uses the contract of indexOf: return -1 when not found.

Mixing primitives and objects: pay attention to types

Unit 1 frequently mixes int, double, and String.

Examples of type-sensitive behavior:

  • "score: " + 5 becomes a String due to concatenation.
  • 5 / 2 is integer division (result 2), but 5 / 2.0 is 2.5.

Even though integer division is often emphasized earlier/later depending on course sequence, it appears naturally when you combine methods like length() (an int) with arithmetic.

Side effects vs returned values (a mindset that prevents bugs)

When you call a void method, the only “result” is what it does (printing, changing an object’s state, etc.). When you call a non-void method, the method produces a value you can use.

With String, most methods are non-void and have no side effects because strings can’t change. With other objects (like Scanner), method calls can change the object’s internal state (for example, moving past tokens in the input). This difference becomes more important later, but Unit 1 is where you start building the habit of asking:

  • Does this method return something I need to store?
  • Does this method change the object I’m calling it on?

A realistic combined example (Math + String)

Suppose you want a random uppercase letter.

Reasoning:

  • Generate random integer 0..25.
  • Map 0..25 to ASCII codes 65..90 is possible, but AP CSA often avoids requiring ASCII memorization.
  • Another approach: store alphabet in a string and use substring.
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int index = (int)(Math.random() * 26);
String letter = alphabet.substring(index, index + 1);
System.out.println(letter);

What can go wrong?

  • If you accidentally use alphabet.substring(index, index) you get "".
  • If your random range is wrong (like 0..26), index + 1 might be out of bounds.
Exam Focus
  • Typical question patterns:
    • Trace multi-line code that combines method calls and arithmetic to determine final output.
    • Fill in a missing line so a code segment produces the intended result.
    • Identify the first line that would cause a runtime error (often index or null related).
  • Common mistakes:
    • Losing track of types in nested expressions (trying to store a double in an int without casting, or using a String where an int is required).
    • Off-by-one errors when computing indices from length().
    • Ignoring return values from non-void methods (especially String methods), expecting the original object to change.