Context:FIT2099_MOC · the one-note Java coding surface — code a class from a blank editor after re-reading this. Depth lives in the linked notes.
Quick Revision
🎯 Objective: write correct, well-encapsulated OO Java ➔ class anatomy + modifiers + collections + inheritance/interfaces + contracts, with the exam gotchas inline.
⚡ Key Constraint: Java is statically typed (types fixed at declaration, checked at compile time) and objects are reference types — most FIT2099 bugs come from reference aliasing, == vs .equals(), and access-widening on override.
🧩 Class Anatomy (execution order)
package game.actors; // 1. package — namespace, MUST be first lineimport java.util.ArrayList; // 2. imports — bring in other packagesimport java.util.List;public class Hero extends Actor implements Speaker { // 3. class header: one extends, many implements public static final int MAX_HP = 100; // 4. static final constant (class-level, assign-once) private int hp; // 5. private field — encapsulated state private final Armour armour; // 6. blank final — assigned exactly once (in ctor) public Hero(Armour armour) { // 7. constructor — runs on `new`; same name, no return type this.armour = armour; // `this` disambiguates field from param this.hp = MAX_HP; } public int getHp() { return hp; } // 8. query (accessor) — no side effect public void takeDamage(int d) { hp -= d; }// 9. command (mutator) — changes state, returns void @Override public String speak() { return "For honour!"; } // 10. override (interface/parent method)}
(Order on the page: package → imports → class → static fields → instance fields → constructors → methods. Compile-time type checking catches type errors before it runs — see Java Static Typing, Java Program Structure.)
object versions; needed for generics; watch autoboxing/null.
Widening cast
double d = anInt;
implicit, safe.
Narrowing cast
int i = (int) aDouble;
explicit, may lose data.
==
a == b
reference identity for objects (same object?); value for primitives.
.equals()
a.equals(b)
value equality; override for your classes. Use for String! (String Pool makes ==sometimes work — trap.)
String
"text"
immutable reference type.
🔁 Control flow & arrays
if (x > 0) {...} else if (...) {...} else {...}String s = (x > 0) ? "pos" : "neg"; // ternaryswitch (day) { case MON: ...; break; default: ...; } // break to avoid fall-throughfor (int i = 0; i < a.length; i++) {...} // index loopfor (int v : a) {...} // for-each (read)while (cond) {...} do {...} while (cond);int[] a = new int[5]; int[] b = {1,2,3}; // .length, 0-based
Practice 1: Model Pet so cats/dogs each make their own sound, with a factory that builds one from a String code, and no switch(type) anywhere. (uses: abstract class + polymorphism + Factory Method + collections)
Reference solution
abstract class Pet { abstract String sound(); }class Cat extends Pet { String sound() { return "miau"; } }class Dog extends Pet { String sound() { return "guau"; } }class PetFactory { static Pet create(String code) { switch (code) { case "C": return new Cat(); case "D": return new Dog(); default: throw new IllegalArgumentException("bad code"); } }}List<Pet> zoo = new ArrayList<>();zoo.add(PetFactory.create("C")); zoo.add(PetFactory.create("D"));for (Pet p : zoo) System.out.println(p.sound()); // miau / guau (dynamic dispatch)
Key move: the switch lives only in the factory; behaviour is chosen by polymorphism, so a new Pet = one subclass + one case, no client edits (OCP).
Practice 2: A BankAccount must reject a negative deposit, keep its balance private and un-leakable, and expose a side-effect-free getBalance(). (uses: encapsulation + validation/exception + CQS + defensive copy of a mutable field)
Reference solution
class BankAccount { private double balance; private final List<Transaction> log; public BankAccount(List<Transaction> initial) { this.log = new ArrayList<>(initial); // defensive copy IN } public void deposit(double amt) { // command if (amt <= 0) throw new IllegalArgumentException("amount must be > 0"); balance += amt; } public double getBalance() { return balance; } // query — no side effect (CQS) public List<Transaction> getLog() { return new ArrayList<>(log); // defensive copy OUT — no privacy leak }}
Key move:throw on precondition breach (fail fast), command vs query kept separate, and the mutable log is copied both in and out so callers can’t alias internal state.
⚠️ Common Mistakes (top of the deduction list)
💡 == on objects/Strings ➔ compares references; use .equals() for value equality.
💡 Access-widening on override ➔ an override may only keep or widen visibility, never narrow.
💡 instanceof/switch(type) in logic ➔ a smell — replace with polymorphism.
💡 Returning a mutable field directly ➔ privacy leak; return a copy.
💡 assert for user input ➔ disabled in prod; use exceptions for client-facing validation.