Java OOP Cheat Sheet
Covers classes, constructors, inheritance, polymorphism, interfaces with default methods, and Java's access modifiers with examples.
Classes & Objects
Define fields, a constructor, and methods, then instantiate an object.
public class Car { private String model; // encapsulated field private int speed; public Car(String model) { // constructor this.model = model; this.speed = 0; } public void accelerate(int amount) { this.speed += amount; } public String getModel() { return model; } // getter}Car myCar = new Car("Tesla"); // instantiationmyCar.accelerate(50);
Inheritance & Polymorphism
Extend a class and override behavior that's resolved at runtime.
public abstract class Shape { public abstract double area(); // must be implemented by subclasses public void describe() { System.out.println("Area: " + area()); }}public class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; }}Shape s = new Circle(3.0); // upcastings.describe(); // polymorphic call - runs Circle's area()
Interfaces
Define a contract, including default and static methods (Java 8+).
public interface Drivable { void drive(); // implicitly public abstract default void honk() { // default method (Java 8+) System.out.println("Beep!"); } static Drivable simple() { // static interface method return () -> System.out.println("Driving..."); }}public class Truck implements Drivable { @Override public void drive() { System.out.println("Truck driving"); }}
Four Pillars of OOP
The core concepts every Java class hierarchy is built on.
- Encapsulation- Hiding internal state behind private fields and exposing controlled access via public methods
- Inheritance- A subclass (extends) reuses and extends the fields/methods of a superclass
- Polymorphism- A superclass reference can invoke overridden subclass behavior at runtime (dynamic dispatch)
- Abstraction- abstract classes and interfaces define a contract without full implementation
- this- Refers to the current instance
- super- Calls the parent class's constructor or overridden method
- @Override- Annotation that verifies a method actually overrides a superclass/interface method
Access Modifiers
Control visibility of fields and methods across classes and packages.
public class Account { public String owner; // accessible from anywhere protected double balance; // accessible in package + subclasses String branch; // package-private (no modifier) private String pin; // accessible only within this class private boolean validatePin(String input) { return input.equals(pin); }}
Records & the equals/hashCode/toString Contract
Records auto-generate value semantics; understand the contract when writing it by hand.
public record Point(int x, int y) { // Compact constructor for validation - no field assignment needed public Point { if (x < 0 || y < 0) throw new IllegalArgumentException("negative coordinate"); }}Point p1 = new Point(1, 2);Point p2 = new Point(1, 2);p1.equals(p2); // true - records compare all componentsp1.hashCode(); // consistent with equals automatically// Manual contract for a regular class:// 1. equal objects MUST have equal hashCodes// 2. equals must be reflexive, symmetric, transitive, consistent@Overridepublic boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Point other)) return false; // pattern-matching instanceof return x == other.x && y == other.y;}@Overridepublic int hashCode() { return Objects.hash(x, y); }
Sealed Classes & Pattern-Matching Switch
Restrict which classes may extend a type, then exhaustively switch over it (Java 17/21+).
public sealed interface Shape permits Circle, Square, Triangle {}public record Circle(double radius) implements Shape {}public record Square(double side) implements Shape {}public record Triangle(double base, double height) implements Shape {}public static double area(Shape shape) { return switch (shape) { case Circle c -> Math.PI * c.radius() * c.radius(); case Square s -> s.side() * s.side(); case Triangle t -> 0.5 * t.base() * t.height(); // no default needed - compiler proves exhaustiveness over permitted types };}
Enums with Per-Constant Method Bodies
An enum constant can override an abstract method, giving each value its own behavior.
public enum Operation { ADD { public int apply(int a, int b) { return a + b; } }, SUBTRACT { public int apply(int a, int b) { return a - b; } }, MULTIPLY { public int apply(int a, int b) { return a * b; } }; public abstract int apply(int a, int b);}int result = Operation.MULTIPLY.apply(3, 4); // 12// Enums also implement interfaces and carry constructor statepublic enum Planet implements Comparable<Planet> { MERCURY(3.3e23), EARTH(5.97e24); private final double mass; Planet(double mass) { this.mass = mass; } public double mass() { return mass; }}
Static Nested, Inner, Local & Anonymous Classes
Four flavors of class nesting, each with different access to the enclosing instance.
public class Outer { private int state = 10; static class StaticNested { // no implicit reference to Outer void show() { System.out.println("static nested"); } } class Inner { // holds an implicit Outer.this reference void show() { System.out.println("state = " + state); } } void demo() { class LocalLogger { // local class - scoped to this method void log(String msg) { System.out.println("[log] " + msg); } } new LocalLogger().log("hi"); Runnable r = new Runnable() { // anonymous class @Override public void run() { System.out.println("running, state=" + state); } }; r.run(); }}Outer.Inner inner = new Outer().new Inner(); // instantiating an inner class externally
Bounded Generics & Wildcards (PECS)
Constrain type parameters and use wildcards to write flexible, variance-safe APIs.
// Bounded type parameter: T must be Comparablepublic static <T extends Comparable<T>> T max(List<T> list) { T best = list.get(0); for (T item : list) if (item.compareTo(best) > 0) best = item; return best;}// PECS: Producer Extends, Consumer Superpublic static double sum(List<? extends Number> producer) { // read-only source double total = 0; for (Number n : producer) total += n.doubleValue(); return total;}public static void fillWithZeros(List<? super Integer> consumer) { // write-only sink for (int i = 0; i < 5; i++) consumer.add(0);}
OOP Gotchas & Object Class Overrides
Subtleties that trip up intermediate Java developers.
- Constructor overload resolution- Java picks the most specific applicable overload at compile time; ambiguous calls with autoboxing/varargs fail to compile
- Overriding vs hiding static methods- Instance methods override polymorphically; static methods are hidden and resolved by the reference's compile-time type
- Covariant return types- An overriding method may narrow its return type to a subtype of the original
- Constructor chaining- this(...) and super(...) must be the first statement in a constructor, and are mutually exclusive
- clone()- Object.clone() does a shallow copy; classes must implement Cloneable or throw CloneNotSupportedException
- finalize() (deprecated)- Removed in favor of try-with-resources / Cleaner; never rely on it for deterministic cleanup
- Diamond problem with default methods- Implementing two interfaces with the same default method forces the class to override and disambiguate explicitly
Favor composition ('has-a', embedding an object as a field) over deep inheritance chains ('is-a') - it keeps classes easier to test and avoids the fragile base class problem where changes to a superclass unexpectedly break distant subclasses.