Skip to content
Part IA Michaelmas Term

OOP Syllabus Checklist

A comprehensive checklist of everything examinable in the Part IA Object-Oriented Programming paper.

Java Language Basics

  • Primitive types (int, double, boolean, char, byte, short, long, float)
  • Reference types (everything else — objects, arrays, strings)
  • Variable declaration and initialisation
  • Arrays (declaration, initialisation, length, for-each loop)
  • Method overloading (same name, different parameter lists — NOT return type)
  • Classes and objects (class as blueprint, new for instantiation)
  • Constructors (default, parameterised, this(), no-arg constructor lost if any constructor is defined)
  • static members (class-level, not instance-level — static fields shared across all instances, static methods cannot access this)
  • Access modifiers (public, protected, default/package-private, private)
  • Encapsulation (private fields + public getters/setters)
  • Immutability (final fields, no setters, defensive copying of mutable fields, class final or constructor private)

Tripos traps

  • static methods cannot be overridden — they can only be hidden/shadowed. Resolution is at compile time based on the reference type, not the object type.
  • Method overloading is compile-time; method overriding is runtime.
  • An array of primitives contains values; an array of objects contains references.

Memory Model

  • Stack vs heap (stack: local variables, method frames, primitive values, references; heap: objects, arrays)
  • References vs pointers (references are abstract handles — no arithmetic, no direct address manipulation)
  • Pass-by-value in Java (the value is passed — for primitives, the value itself; for references, the reference value is copied, so the method cannot change which object the caller’s variable points to, but can mutate the object)
  • Garbage collection (automatic, unreachable objects are collected; System.gc() is a hint only)

Tripos traps

  • Java is always pass-by-value. For objects, the reference is passed by value. This means you cannot make a method swap two object references, but you can mutate the object’s state.

Inheritance

  • extends keyword (single inheritance of implementation)
  • super (call superclass constructor — must be first line; access superclass methods/fields)
  • Method overriding (same name, same parameters, same return type or covariant — @Override annotation)
  • Overriding vs shadowing (methods override by instance type; fields and static methods shadow by reference type)
  • abstract classes (cannot be instantiated; may have abstract methods; may have concrete methods)
  • abstract methods (no body; must be overridden in concrete subclass)
  • final classes (cannot be subclassed)
  • final methods (cannot be overridden)
  • Inheritance of implementation vs inheritance of interface
  • Interfaces (implements; all methods implicitly public abstract before Java 8)
  • Single vs multiple inheritance (Java: single inheritance of implementation, multiple inheritance of interface)
  • The diamond problem (two paths to the same base — Java resolves with single implementation inheritance + default methods with explicit override required)
  • default methods in interfaces (Java 8+; provide method body; can be overridden; resolve ambiguity with Interface.super.method())

Tripos traps

  • Fields are never overridden — they are shadowed. super.field accesses the superclass field; this.field accesses the subclass field.
  • A static method with the same signature in a subclass hides the superclass version. Which one runs depends on the reference type, not the object type.

Polymorphism

  • Static (compile-time) polymorphism: method overloading
  • Dynamic (runtime) polymorphism: method overriding, dynamic dispatch
  • Dynamic dispatch mechanism (vtable: each object has a reference to its class’s vtable; the JVM looks up the actual method to call at runtime based on the object’s concrete class)
  • Upcasting (implicit — treating a subclass object as superclass type)
  • Downcasting (explicit — (Subclass) superRef; may throw ClassCastException)
  • instanceof check before downcasting

Tripos traps

  • Dynamic dispatch applies only to instance methods, not to fields, static methods, or private methods.
  • Animal a = new Dog(); a.makeSound(); — the runtime type Dog determines which makeSound() runs. But a.name (if name is a field) uses the compile-time type Animal.

Dynamic dispatch: vtable lookup at runtime

OOP Principles

  • Single Responsibility Principle (SRP): A class should have exactly one reason to change. Each class does one well-defined thing.
  • Open-Closed Principle (OCP): Classes should be open for extension but closed for modification. Add new behaviour by adding new code, not by changing existing code.
  • Liskov Substitution Principle (LSP): Subtypes must be substitutable for their base types without altering correctness. A subclass should not strengthen preconditions or weaken postconditions.
  • Cohesion: how closely related the responsibilities of a class are. High cohesion (good) — all methods and fields serve a single, well-defined purpose. Low cohesion (bad) — a class does many unrelated things.
  • Coupling: the degree of interdependence between classes. Loose/low coupling (good) — classes know little about each other, interact through interfaces. High/tight coupling (bad) — changing one class forces changes in many others.

Tripos traps

  • LSP violations often come from strengthening preconditions (e.g., a subclass requires a parameter that the superclass does not) or weakening postconditions.
  • SRP violations often come from mixing business logic with persistence, or mixing computation with display.

Object Lifecycle

  • Object creation: new allocates memory on the heap, calls the constructor chain (subclass → superclass all the way to Object)
  • Garbage collection: automatic; objects become eligible when no live references point to them
  • Mark-and-sweep algorithm: (1) Mark phase — trace all reachable objects from root set (stack, static fields). (2) Sweep phase — reclaim unmarked objects.
  • finalize() — deprecated; called by GC before object is reclaimed; unpredictable timing; not for resource cleanup
  • Shallow copy vs deep copy (shallow: copy references, not objects; deep: recursively copy referenced objects)
  • clone()Object.clone() does shallow copy; must implement Cloneable; override clone() for deep copy
  • Copy constructors — public MyClass(MyClass other) — preferred over clone()

Tripos traps

  • finalize() is deprecated in Java 9+ and should not be relied upon. Use try-with-resources for resource cleanup.
  • clone() is fragile — use a copy constructor instead.

Collections and Comparisons

  • Collection interfaces: List (ordered, allows duplicates), Set (no duplicates), Map (key-value pairs), Queue (FIFO)
  • Common implementations: ArrayList (dynamic array, O(1)O(1) random access, O(n)O(n) insertion/removal from middle), LinkedList (doubly-linked, O(1)O(1) insertion/removal at ends, O(n)O(n) random access), HashSet/HashMap (O(1)O(1) average operations, unordered), TreeSet/TreeMap (O(logn)O(\log n), sorted)
  • == vs .equals() (== compares references/identity; .equals() compares logical equality — must override for custom classes)
  • hashCode contract: if a.equals(b), then a.hashCode() == b.hashCode(). The converse is not required. Both must be overridden together.
  • Comparable<T>int compareTo(T other) — defines natural ordering (one ordering per class)
  • Comparator<T>int compare(T a, T b) — defines external ordering (multiple comparators per class)

Tripos traps

  • If you override equals() but not hashCode(), HashSet and HashMap will misbehave — two equal objects can end up in different buckets.
  • Comparable is implemented by the class being compared; Comparator is a separate class that compares other objects.

Generics

  • Type parameters: class Box<T> { T value; }
  • Type erasure: at runtime, type parameters are erased to their bounds (e.g., <T>Object, <T extends Number>Number). The JVM never sees the type parameter.
  • Why erasure? Backward compatibility — Java 5 generics had to work with pre-generics bytecode.
  • Covariance: Integer[] is a subtype of Number[] (arrays are covariant — a runtime type check prevents storing the wrong type).
  • Invariance: List<Integer> is NOT a subtype of List<Number> (generics are invariant — prevents the array covariance problem at the type level).
  • Wildcards:
    • ? — unbounded wildcard; read-only (except null)
    • ? extends T — upper-bounded; producer (you can read T from it, cannot write)
    • ? super T — lower-bounded; consumer (you can write T to it, can only read Object)
  • PECS: Producer Extends, Consumer Super
  • Type bounds: <T extends Comparable<T>> — T must implement Comparable<T>

Tripos traps

  • List<String> and List<Integer> have the same runtime type (List). Overloading on different generic parameters does not work because they erase to the same signature.
  • Generic type information is not available at runtime. You cannot do if (obj instanceof List<String>).

Exceptions

  • Exception hierarchy: ThrowableError (unrecoverable — OutOfMemoryError, StackOverflowError) and ExceptionRuntimeException (unchecked — NullPointerException, IndexOutOfBoundsException) and checked exceptions (IOException, SQLException)
  • Checked vs unchecked: checked exceptions must be caught or declared in throws clause; unchecked exceptions do not need to be
  • try-catch-finally: finally always executes (even after return, even after exception) — except for System.exit() or JVM crash
  • try-with-resources: try (Resource r = new Resource()) { ... } — automatically calls close() when the block exits; resource must implement AutoCloseable
  • Exception guidelines: catch specific exceptions, not Exception; never swallow exceptions silently; exceptions are for exceptional conditions, not flow control
  • Assertions: assert condition : "message"; — disabled at runtime by default (enable with -ea); for debugging invariants, not for production error handling

Java exception hierarchy — Throwable tree

Tripos traps

  • Using exceptions for control flow (e.g., catching ClassCastException instead of using instanceof) is an anti-pattern. Exceptions are for exceptional situations.
  • A finally block that throws an exception will mask any exception thrown in the try block.

Design Patterns

  • Composite: Treat one object and group of objects uniformly through a shared interface
  • Decorator: Add responsibilities to individual objects dynamically by wrapping
  • State: Object changes behaviour when its internal state changes (delegates to state objects)
  • Strategy: Interchangeable algorithms selected externally by the client
  • Singleton: Exactly one instance with global access (private constructor + static factory)
  • Observer: Notify many dependents automatically when subject’s state changes
  • Optional<T>: Container for possibly-absent value; avoids null; designed for method return types

Design patterns overview

Tripos traps

  • State and Strategy are structurally identical — distinguish by intent (internal state change vs external algorithm choice).
  • Always tie patterns to OCP or another principle. A pattern without justification is only half an answer.

Lambdas and Streams

  • Lambda expressions: (params) -> expression or (params) -> { statements; }
  • Functional interfaces: interfaces with exactly one abstract method (SAM type)
  • @FunctionalInterface annotation
  • Built-in functional interfaces: Function<T,R>, Predicate<T>, Consumer<T>, Supplier<T>, BiFunction<T,U,R>, UnaryOperator<T>, BinaryOperator<T>
  • Method references: Class::staticMethod, instance::method, Class::instanceMethod, Class::new
  • External vs internal iteration
  • Streams: lazy, single-use pipelines (not data structures)
  • Intermediate operations: filter, map, flatMap, sorted, distinct, limit, skip, peek
  • Terminal operations: forEach, collect, reduce, count, anyMatch/allMatch/noneMatch, findFirst/findAny
  • Laziness: nothing runs until a terminal operation
  • Short-circuiting: limit, findFirst, anyMatch
  • Parallel streams: parallelStream() for CPU-intensive, stateless, large-dataset operations
  • Collectors: toList(), toSet(), toMap(), groupingBy(), joining()

Stream pipeline: intermediate and terminal operations

Tripos traps

  • An intermediate operation without a terminal operation does nothing.
  • Streams are single-use — cannot reuse after a terminal operation.
  • forEach on a parallel stream does not guarantee order. Use forEachOrdered.

UML

  • Class diagrams: class name, fields (name: type), methods (name(params): return)
  • Relationships: association (solid line), inheritance/extends (solid line with hollow triangle), implements (dashed line with hollow triangle), aggregation (hollow diamond), composition (filled diamond)
  • Visibility: + public, - private, # protected
  • Abstract classes and methods in italics

UML class diagram notation

How to use this checklist

For each topic, you should be able to:

  1. Define the concept in one sentence.
  2. Write a short code example.
  3. Identify the common Tripos traps and explain why they happen.
  4. Connect the concept to at least one design principle (OCP, LSP, SRP, loose coupling, high cohesion).