CS2312 Test 1: Prep Book

Fri 9 Oct 09:30 · BOC R4057 · 50 min · closed book, pen + paper · 0% or 5% · up to Week 5 lecture + Lab 03 · ≥15 min late = not let in

How to use it: cover the answer, write yours on paper, then open answer. Anything you got wrong goes on one sheet you re-read tomorrow at breakfast. The Day class, traps table, Scanner and Lab 3 code are on the mock notes page. This book only adds what the mock skipped plus practice.

Tonight (TickTick blocks)

WhenDoUses
17:10–17:55Topics 01–03 lecture exercises, closed book§Week 5 below + mock notes
18:00–18:50Lab03 by hand + redo what you lost on the mockP1, P2
19:30–20:20Timed 50-min run, pen onlyP1 (25 min) → P2–P4 (25 min)
after5 min on the traps, pack bag, check seating plan, sleep§Morning of

What the paper looks like

From the 2016-17 Quiz 1 (Lab02 Q5 given files) + Helena's drawing instructions; this year's mock had the same shape

Week 5 lecture: the part the mock didn't cover

Lecture Exercise (Handout_LecWk05Ex), Topic 03 p7–p16; written answers = Writing_LecWk06_Q0*.jpg

Q1 · toString through a chain

class X { private int xValue; private X xChild;
  public X(int v, X c) { xValue = v; xChild = c; }
  public String toString() { return xChild + " " + xValue; } }
X obj = new X(99, new X(88, new X(77, null)));
System.out.println(obj);
answer

null 77 88 99. xChild + " " calls the child's toString() first (recursion), innermost child is null which prints as null. Built inside-out, printed innermost-first.

Q2 · implicit vs explicit parameter

class X { private int data;
  public X(int d) { data = d * 2; }
  public void doSomething(X r) {
    X s = new X(8);
    System.out.println(this.data); System.out.println(r.data); System.out.println(s.data); } }
X a = new X(1); X b = new X(15); a.doSomething(b);
answer

Q3 · does setName change the String?

Employee e = new Employee("Carl Cracker", 75000, 1987, 12, 15);
e.setName("Helena");
answer

No. Strings are immutable. setName does name = n;, which re-points the name field at a different String object "Helena". Drawing: e → Employee{ name ─╳→ "Carl Cracker", name → "Helena", salary 75000, hireDay → Day{1987,12,15} }. The old "Carl Cracker" has no arrow → garbage.

Q4 · static vs instance

class A { public int x1; public static int x2;
  public void m1() { m2(); }
  public static void m2() {
    //x1 += 100;   // line X1
    x2 += 100;
    //m1();        // line X2
  } }
(new A()).m1(); (new A()).m1();
answer

Q5 · "The constructor RandomNumber() is undefined"

public class RandomNumber {
  private int r = (int)(Math.random() * 100);
  public RandomNumber(int n) { r = (int)(Math.random() * n); }
  ...
  new RandomNumber();   // ERROR
answer

Java only generates the no-argument default constructor if you write no constructor. Writing RandomNumber(int n) removes it. Fix: add public RandomNumber() { } (the field initialiser already gives 0..99), or public RandomNumber() { this(100); }.

Q6 · casting

int i = 97; char c; c = (char)i;   // println(i) → 97, println(c) → a
answer

(i) Does i's type change? No, a variable's type is fixed at declaration. (ii) Accurate: (b), (c), (d). (a) "convert i to char" is the wrong one: i itself isn't converted, its value is used to produce a char value.


P1 · File + arrays (≈25 min, the big one)

2016-17 Quiz 1 Q1, 25 marks. Source PDF: Labs/Lab02_GivenFiles/Lab02_Q5(201617AQuiz1Q1)/

StudentList.txt has 20 student IDs. AttendanceLog.txt has 20 numbers: an ID of someone present, or 0 = empty seat. Some attendees are walk-ins (not on the list). Avoid hardcoding except the size 20.

public static void main(String[] args) {
  Scanner s = new Scanner(System.in);
  Attendance at = new Attendance();
  System.out.print("Type the student ID to search: ");
  int id = s.nextInt();
  if (at.belongToClass(id) == false) System.out.println("Result: Not belong to the class.\n");
  else if (at.isPresent(id))         System.out.println("Result: The student is present.\n");
  else                               System.out.println("Result: No show!\n");
  s.close();
}
// (b) second main:  at.listAbsentees();  at.listWalkIn();
// List of absentees: / 52608757 / ... / Total count: 5
// List of walk-in students: / 54756947 / ...

Write: (i) constructor reading both files, (ii) isPresent, (iii) belongToClass, (iv) listAbsentees, (v) listWalkIn.

answer
import java.io.*;
import java.util.Scanner;

public class Attendance {
  private int[] students;
  private int[] attendees;

  public Attendance() throws FileNotFoundException {   // ← new File(..) needs this (and main too)
    students = new int[20];
    attendees = new int[20];
    Scanner sStudents = new Scanner(new File("StudentList.txt"));
    Scanner sAttendees = new Scanner(new File("AttendanceLog.txt"));
    for (int i = 0; i < students.length; i++) students[i] = sStudents.nextInt();
    for (int i = 0; i < attendees.length; i++) attendees[i] = sAttendees.nextInt();
    sStudents.close();
    sAttendees.close();
  }

  public boolean isPresent(int id) {
    for (int i = 0; i < attendees.length; i++)
      if (attendees[i] == id) return true;
    return false;                       // after the loop, NOT in an else inside it
  }

  public boolean belongToClass(int id) {
    for (int i = 0; i < students.length; i++)
      if (students[i] == id) return true;
    return false;
  }

  public void listAbsentees() {
    System.out.println("List of absentees:");
    int count = 0;
    for (int i = 0; i < students.length; i++)
      if (!isPresent(students[i])) {    // reuse (ii), don't re-write the search
        System.out.println(students[i]);
        count++;
      }
    System.out.println("Total count: " + count);
  }

  public void listWalkIn() {
    System.out.println("List of walk-in students:");
    for (int i = 0; i < attendees.length; i++)
      if (attendees[i] != 0 && !belongToClass(attendees[i]))   // 0 = nobody, skip it
        System.out.println(attendees[i]);
  }
}

Where marks go: throws FileNotFoundException; loop bound .length not 20; return false after the loop; reusing isPresent/belongToClass; skipping the 0s in walk-ins; closing both Scanners.

P2 · Memory drawing (≈7 min)

class Student { private String name; public Student(String n) { name = n; } }
class Team { private String name; private Student[] members;
  public Team(String n, Student[] m) { name = n; members = m; } }

public static void main(String[] args) {
  Student s1 = new Student("Ada");
  Student s2 = new Student("Bob");
  Student[] mem = new Student[3];
  mem[0] = s1;
  mem[1] = s2;
  Team t = new Team("Team " + (char)('A' + 0), mem);
  s2 = new Student("Cy");
}

Draw all variables in main() and every object at the end. Which objects are garbage?

answer

P3 · Traces (≈8 min, write the exact output)

// (a) uses the Day class
Day a = new Day(2024, 2, 28);
Day b = a;
a.advance();
b = b.next();
a.next();
System.out.println(a + " / " + b);

// (b)
System.out.println(1 + 2 + "3" + 4 + 5);

// (c)
class C { static int n = 0; int id; C() { n++; id = n; } }
C x = new C(), y = new C(), z = x;
System.out.println(x.id + " " + y.id + " " + z.id + " " + C.n);

// (d) input typed:  12 Ada Lee⏎
int k = in.nextInt();
String s = in.nextLine();
System.out.println("[" + s + "]");

// (e)
static void swap(Day p, Day q) { Day t = p; p = q; q = t; }
Day d1 = new Day(2025,1,1), d2 = new Day(2026,1,1);
swap(d1, d2);
System.out.println(d1);

// (f)
int i = 5, cnt = 0;
while (i > 0) { i -= 2; cnt++; }
System.out.println(i + " " + cnt);
answer
#OutputWhy
a29 Feb 2024 / 1 Mar 20242024 is leap; advance moves the shared object (a and b both 29 Feb); b = b.next() gives b a new object; bare a.next() is thrown away (garbage)
b3345left to right: 1+2=3 (int), then string concat "3"+"3"+"4"+"5"
c1 2 1 2n is shared (static), z is an alias of x, no third object
d[ Ada Lee]nextLine takes the rest of the line incl. the leading space
e1 Jan 2025p, q are copies of the references; swapping copies doesn't touch d1/d2
f-1 35→3→1→-1, three iterations

P4 · Find the bugs (≈5 min)

public class Point {
  private int x, y;
  public void Point(int x, int y) { x = x; y = y; }        // (1)
  public static double dist(Point p) {
    return Math.sqrt(x * x + y * y);                       // (2)
  }
  public boolean same(Point o) { return this == o; }       // (3)
  public String toString() { "(" + x + "," + y + ")"; }    // (4)
}
Point p = new Point(3, 4);                                 // (5)
String s1 = "ab", s2 = new String("ab");
if (s1 == s2) System.out.println("same");                 // (6)
answer
  1. void makes it a method named Point, not a constructor. And x = x assigns the parameter to itself → use this.x = x; this.y = y;
  2. Static method has no object: x/y don't exist here → p.x, p.y.
  3. Compiles, but it's a logic bug if "same" means same coordinates: == checks alias. Use x == o.x && y == o.y.
  4. Missing return → compile error (also "not a statement").
  5. Because of (1) there is no Point(int,int) constructor → "constructor Point(int, int) is undefined".
  6. Prints nothing: different objects. Use s1.equals(s2).

P5 · Day class from a blank page (≈12 min, do it once tonight)

Without looking: fields, Day(y,m,d), Day(y) via this(...), static isLeapYear, static valid(y,m,d) + instance valid(), next() (new object), advance() (mutates), toString() as 28 Jan 2014. Then check against the mock notes Day class. Count every difference.

Lab 03 variant: static Day[] createDayListFromFile(String path): first number = n, then n lines of y m d; list valid ones, then invalid ones, reading the file once. Answer on the mock notes.


Morning of