Difficulty: Intermediate
Prerequisites: Java Expression Evaluation and Type Rules (the companion study notes), basic understanding of arrays and loops.
Code tracing is the largest section of the CS 312 exam, typically worth 24 points. You are given Java snippets and must determine the exact output, including handling compile errors, runtime errors, and infinite loops. The questions test your ability to simulate Java execution by hand: tracking variable values, understanding how arrays and objects are passed to methods, and knowing which version of an overridden method runs. If you have not yet studied expression evaluation rules, start there.
Code tracing questions ask you to execute Java by hand and write the exact output. The main traps are: arrays are passed by reference (changes inside a method stick), Strings are immutable (methods return new objects, they do not change the original), and polymorphism means the runtime type determines which overridden method runs, not the declared type.
Pass by value (primitives)
Java copies the value of a primitive (int, double, boolean, char) into the method parameter. Changes to the parameter inside the method have no effect on the original variable.
Think of it as: the method gets its own photocopy.
Pass by value of references (arrays and objects)
Java copies the reference (the memory address) into the method parameter. The method can modify the object's contents through this reference, and those changes are visible to the caller. However, reassigning the parameter to a new object inside the method does not change the caller's variable.
Think of it as: two people holding the same leash. Either can tug the dog, but if one drops the leash and grabs a different dog, the other still has the original.
Default array values
new int[n] initialises every element to 0. new boolean[n] initialises every element to false. new String[n] (or any object array) initialises every element to null.
For-each loop
Iterates over every element of an array or collection. The loop variable is a copy of each element, so assigning to it does not change the underlying array.
ArrayList
A resizable list. Key methods: add(element), add(index, element), remove(index), remove(Object), get(index), size(). The constructor new ArrayList<>(5) sets initial capacity, not size; size() still returns 0.
In simple terms: capacity is the space reserved behind the scenes; size is how many items are currently in the list.
Enum
A fixed set of named constants. values() returns an array of all constants in declaration order. Accessing by index: MyEnum.values()[2] gives the third constant.
Inheritance and polymorphism
A subclass inherits methods and fields from its superclass. When a method is overridden, the version that runs is determined by the actual object type at runtime, not the declared variable type. super.method() calls the parent's version explicitly.
== on objects (reference equality)
Compares whether two variables point to the exact same object in memory. Two objects with identical contents are still not == unless they are literally the same object. The default equals() from Object also uses ==; a class must override it for content comparison.
String immutability
String methods like substring(), toUpperCase(), and replace() return new String objects. The original String is never modified. Calling d2.substring(1) without storing the result changes nothing.
When an array is passed to a method, the method receives a copy of the reference, so mutations to the array's elements are visible to the caller.
Trace example: int[] a1 = {5, 2, 4, 6, 1}; a(a1); where the method modifies elements in place. Work through each line tracking the array state. After the method returns, System.out.print(Arrays.toString(a1)) shows the mutated array.
Track each index carefully. When a line says arr[arr[1]] += 3, first resolve arr[1] to get the index, then modify that element.
The worked answer: starting with {5,2,4,6,1}, after the method runs the output is [7, 2, 7, 7, 1].
A for-each loop copies each element into the loop variable. Modifying the loop variable does not modify the array.
double[] b1 = {.5, 2, 1.5}; double tot1 = 0.0; for (double a : b1) { tot1 += a; } simply sums the array. Output: 4.0 2.0.
Track both the loop condition and variable updates carefully.
Example: int c1 = 80; int t2 = 0; while (c1 > 0 && t2 < 20) { t2++; c1 /= 2; }. After 7 iterations c1 reaches 0, so the loop stops. Output: 0 7.
String d3 = d1.substring(4) creates a new String object. d4 = d2 makes d4 point to the same object as d2.
d2.substring(1) returns a new String but the result is discarded (not assigned).
d2 == d4 is true (same reference). d1 == d3 is false (different objects, even though d3 contains part of d1's text).
Output: true false.
boolean[] es = new boolean[6] fills with false. es[3] == es[4] is true (both false). Output: false true.
String[][] namTab = new String[10][4] has namTab.length = 10, and each row has length 4. Summing row lengths gives 40. Output: 10 40.
g() Method Pattern (Cumulative Array Modification)The method g() adds all previous elements to each current element:
public static void g(int[] arr) {
for (int i = 0; i < arr.length; i++)
for (int j = 0; j < i; j++)
arr[i] += arr[j];
}For {5}, the inner loop never runs. Output: [5].
For {2, 1, 4}: index 0 unchanged (2). Index 1 adds arr[0]: 1+2=3. Index 2 adds arr[0] then arr[1]: 4+2=6, 6+3=9. Output: [2, 3, 9].
For {1,1,1,1,1,2}: each element accumulates all previous (which double each step). Output: [1, 2, 4, 8, 16, 34].
For {-3,0,5,-2,7,-10}: trace carefully. Output: [-3, -3, -1, -7, -14, -38].
CS_Area.values().length returns 3 (three constants). CS_Area.values()[2] returns SYSTEMS (zero-indexed). Output: 3 SYSTEMS.
va++ on an array variable is a compile error. You cannot increment an array reference.
Object obj = Room() is a syntax error: missing new.
Meeting m1 = new Object(5) is a syntax error: Object is not a Meeting.
Meeting m2 = new Classroom(10, 10) is a syntax error: Classroom does not extend Meeting.
Trace add, add(index, element), remove(index), and remove(Object) step by step.
remove(Object) removes the first occurrence and returns true/false.
new ArrayList<>(5) sets capacity to 5 but size() is still 0.
Worked example M: after all operations, output is [K, B, A, G].
Worked example N: xs.size() outputs 0.
Constructor chaining: new Classroom(10, 10) calls super(10 * 2), so seats = 20.
Method override: Classroom does not override expand(), so it inherits Room's version (seats += 5). Meeting overrides expand() to set tele = true without changing seats.
Polymorphism: Room cs = new Meeting(10); cs.expand(); calls Meeting's expand() because the runtime type is Meeting. Output: room: 10 true.
Private fields: qr.seats -= 5 is a compile error because seats is private in Room.
Reference aliasing: cr2 = cr1 makes both variables point to the same Classroom object. Subsequent calls to expand() on either variable affect the same object.
equals() default: Unless overridden, equals() uses ==. Two Classroom objects with identical contents are not equals(). But toString().equals(toString()) compares the String content, which is true.
When a method modifies an array parameter and returns a value, the modifications persist in the caller's array. In question X, um(ua, 2) modifies ua before um(ua, 1) is called, so the second call works on the already-modified array.
Output for X: [-2, 4]2 4 [-2, 5]-2 5 3.
The print inside um runs first, then its return value is used in the outer print expression.
Students often think reassigning a parameter inside a method changes the caller's variable. It does not. r = new Room(0) inside a method only changes the local parameter r. The caller's reference still points to the original object.
Students often think d2.substring(1) modifies d2. Strings are immutable. The method returns a new String; if you do not store it, nothing changes.
Students often think new ArrayList<>(5) creates a list with 5 elements. It creates an empty list with capacity for 5. size() returns 0.
Students often think remove("G") on an ArrayList removes all occurrences. It removes only the first match.
Students often think == checks whether two objects have the same content. It checks whether they are the same object in memory. Use .equals() for content comparison, and only if the class overrides it.
True or false: If a method receives an array parameter and modifies its elements, the caller's array is changed. (True.)
True or false: new int[5] creates an array where all values are 0. (True.)
Fill in the blank: new boolean[3] initialises every element to ___. (false)
True or false: "abc".toUpperCase() modifies the original String. (False. It returns a new String.)
True or false: If cr2 = cr1, calling cr2.expand() also affects what cr1 sees. (True. They point to the same object.)
Q: What is the output of snippet Q? (Classroom c3 = new Classroom(10, 10); c3.add(2); System.out.print(c3);)
A: room: 30. The constructor calls super(10 * 2), so seats = 20. add(2) sets plugs += 2, then calls expand() twice. Classroom inherits Room's expand(), so seats += 5 twice. Seats becomes 30. toString() is inherited from Room: "room: 30".
Q: What is the output of snippet R? (Room or passed to method o which calls r.expand() twice)
A: room: 30. The Room starts with 20 seats. expand() adds 5 twice (20 + 5 + 5 = 30). Because arrays and objects are passed by reference, the change persists.
Q: What is the output of snippet S? (Room pr passed to method p which calls r.expand() then r = new Room(0))
A: room: 25. The expand adds 5 (20 to 25). Then r = new Room(0) only changes the local parameter. The caller's pr still points to the Room with 25 seats.
Q: What is the output of snippet T? (Room qr = new Room(10); qr.seats -= 5;)
A: COMPILE ERROR. seats is private in Room. Outside code cannot access it directly.
Q: What is the output of snippet U? (Two Classrooms, reference aliasing, then expand calls)
A: room: 20. cr1 starts with seats = 10 (52). cr2 starts with seats = 20 (102). cr2.expand() adds 5 to cr2 (25), but then cr2 = cr1 makes both point to cr1's object (seats=10). cr1.expand() adds 5 (15). cr2.expand() adds 5 again to the same object (20). Output: room: 20.
Q: What is the output of snippet V? (Room cs = new Meeting(10); cs.expand();)
A: room: 10 true. The runtime type is Meeting. expand() is overridden in Meeting to set tele = true without changing seats. toString() is overridden in Meeting to append tele.
Q: What is the output of snippet W? (Two identical Classrooms compared with toString().equals() and equals())
A: true false. ct1.toString().equals(ct2.toString()) compares String content (both "room: 20"), so true. ct1.equals(ct2) uses the default Object equals(), which is ==, so false (different objects).
Code tracing draws on every other topic in the course. Expression evaluation (Doc 1) underpins every line you trace. The OOP questions connect to inheritance, polymorphism, and encapsulation concepts. Array manipulation patterns here reappear in the programming problems (Doc 3) where you write similar code yourself.
Java code tracing, CS 312 exam output questions, array pass by reference Java, String immutability, ArrayList add remove get, for-each loop Java, while loop tracing, enum values() Java, inheritance polymorphism override, super keyword, == vs equals objects, default array values, compile error runtime error infinite loop, reference aliasing Java, constructor chaining super