Java Cheatsheet

Inheritance and Interfaces

Use this Java reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

extends — Class Inheritance

Java supports single class inheritance.

public class Animal {
    protected String name;
    private int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age  = age;
    }

    public void speak() { System.out.println(name + " makes a sound."); }
    public int  getAge()  { return age; }

    @Override public String toString() { return name + " (age " + age + ")"; }
}

public class Dog extends Animal {
    private String breed;

    public Dog(String name, int age, String breed) {
        super(name, age);       // must be FIRST statement in constructor
        this.breed = breed;
    }

    @Override
    public void speak() { System.out.println(name + " barks!"); }

    public String getBreed() { return breed; }
}

Dog d = new Dog("Rex", 3, "Labrador");
d.speak();           // "Rex barks!"   — overridden
d.getAge();          // 3              — inherited
d instanceof Animal  // true
d instanceof Dog     // true

Method Overriding

class Shape {
    public double area() { return 0; }
}

class Circle extends Shape {
    private double r;
    Circle(double r) { this.r = r; }

    @Override               // annotation enforced by compiler — catches typos
    public double area() { return Math.PI * r * r; }
}

Rules for overriding: - Same name, same parameter types (same signature). - Return type must be the same or a covariant (narrower) subtype. - Access modifier must be the same or less restrictive. - Cannot throw broader checked exceptions. - Cannot override static, final, or private methods.

super Keyword

class Parent {
    String greet() { return "Hello from Parent"; }
}

class Child extends Parent {
    @Override
    String greet() {
        return super.greet() + " and Child";  // call parent version
    }

    Child() {
        super();  // implicit if omitted and parent has no-arg ctor
    }
}

super — accesses parent class fields, methods, or constructor. super.method() — calls parent's version of an instance method. super(args) — calls parent constructor (must be first line).

Abstract Classes

public abstract class Shape {
    abstract double area();             // no body — subclass must implement
    abstract double perimeter();

    // Can have concrete methods
    public void describe() {
        System.out.printf("Area=%.2f, Perimeter=%.2f%n", area(), perimeter());
    }

    // Can have constructors, fields, static members
    protected String color = "black";
}

public class Square extends Shape {
    private double side;
    Square(double side) { this.side = side; }

    @Override double area()      { return side * side; }
    @Override double perimeter() { return 4 * side;    }
}

// Cannot instantiate abstract class:
// new Shape();  // compile error

Interfaces

public interface Drawable {
    void draw();                                          // abstract (always public)
    double getArea();

    // Default method (Java 8+) — has a body, can be overridden
    default String description() {
        return "A drawable with area " + getArea();
    }

    // Static method (Java 8+) — called on the interface, not instances
    static Drawable empty() { return () -> {}; }

    // Constants
    int VERSION = 1;   // implicitly public static final
}

// Implementing an interface
public class Circle implements Drawable {
    private double radius;
    Circle(double r) { this.radius = r; }

    @Override public void   draw()    { System.out.println("drawing circle"); }
    @Override public double getArea() { return Math.PI * radius * radius; }
}

Implementing Multiple Interfaces

interface Flyable { void fly(); }
interface Swimmable { void swim(); }

class Duck extends Animal implements Flyable, Swimmable {
    @Override public void fly()  { System.out.println("Duck flying"); }
    @Override public void swim() { System.out.println("Duck swimming"); }
}

Interface Default Method Conflict Resolution

interface A { default void greet() { System.out.println("A"); } }
interface B { default void greet() { System.out.println("B"); } }

class C implements A, B {
    @Override
    public void greet() {
        A.super.greet();  // explicitly choose which default to call
    }
}

Interface vs. Abstract Class

FeatureAbstract ClassInterface
Multiple inheritanceNo (single extends)Yes (implements many)
ConstructorsYesNo
Instance fieldsYesNo (constants only)
Method bodiesYesOnly default and static
Access modifiers on methodsAnyAlways public (abstract)
Use whenIS-A + shared stateCAN-DO capability contract

Polymorphism

// Runtime dispatch (dynamic binding)
Shape s = new Circle(5.0);   // compile-type Shape, runtime Circle
s.area();                    // calls Circle.area() — virtual dispatch

// Collections of mixed subtypes
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(3));
shapes.add(new Square(4));
shapes.add(new Triangle(3, 4, 5));

for (Shape shape : shapes) {
    shape.describe();         // each calls its own area() and perimeter()
}

final Keyword

final class Immutable { ... }      // cannot be subclassed
final void doIt() { ... }          // cannot be overridden
final int MAX = 100;               // constant field

Sealed Classes and Interfaces (Java 17+)

sealed interface Expr permits Num, Add, Mul {}

record Num(int value)           implements Expr {}
record Add(Expr left, Expr right) implements Expr {}
record Mul(Expr left, Expr right) implements Expr {}

// Exhaustive pattern switch (Java 21+)
int eval(Expr e) {
    return switch (e) {
        case Num(int v)         -> v;
        case Add(Expr l, Expr r) -> eval(l) + eval(r);
        case Mul(Expr l, Expr r) -> eval(l) * eval(r);
    };
}

Permitted subclasses must be in the same package (or module). Subclasses must be final, sealed, or non-sealed.

Casting and instanceof with Inheritance

Animal a = new Dog("Rex", 3, "Lab");

// Upcast (always safe, implicit)
Animal ref = new Dog("Rex", 3, "Lab");

// Downcast (requires explicit cast; fails at runtime if wrong)
Dog d = (Dog) ref;              // OK if ref actually holds a Dog
Cat c = (Cat) ref;              // ClassCastException!

// Safe downcast pattern
if (ref instanceof Dog dog) {   // pattern matching (Java 16+)
    dog.getBreed();
}

Interfaces as Types

// Use interface type to decouple
List<Integer> list = new ArrayList<>();   // interface = List, impl = ArrayList
Comparator<String> cmp = String::compareToIgnoreCase;
Iterable<String> iter = Set.of("a","b");

// Method accepting interface type
public static void printAll(Iterable<?> items) {
    for (var item : items) System.out.println(item);
}
printAll(List.of(1,2,3));
printAll(Set.of("x","y"));

Functional Interfaces and Inheritance

// A @FunctionalInterface can extend another, as long as no new abstract method is added
@FunctionalInterface
interface StringMapper extends Function<String, String> {}

StringMapper upper = String::toUpperCase;

Marker Interfaces

Interfaces with no methods — signal a capability to the JVM or frameworks.

Serializable     // java.io — object can be serialized
Cloneable        // java.lang — clone() is allowed
RandomAccess     // java.util — list supports O(1) get
Remote           // java.rmi — object can be used remotely

Constructor Chaining with Inheritance

class Vehicle {
    String brand;
    Vehicle(String brand) { this.brand = brand; }
}

class Car extends Vehicle {
    int doors;
    Car(String brand, int doors) {
        super(brand);           // super() call must be first
        this.doors = doors;
    }
}

class ElectricCar extends Car {
    int range;
    ElectricCar(String brand, int doors, int range) {
        super(brand, doors);    // chains to Car constructor
        this.range = range;
    }
}

Practical Patterns

// Template Method Pattern — define skeleton, subclasses fill in steps
abstract class DataProcessor {
    final void process() {   // final: subclasses can't change the flow
        readData();
        processData();
        writeData();
    }
    abstract void readData();
    abstract void processData();
    abstract void writeData();
}

// Strategy Pattern via interface
interface SortStrategy {
    void sort(int[] arr);
}
class BubbleSort implements SortStrategy {
    @Override public void sort(int[] arr) { /* bubble sort */ }
}
class QuickSort implements SortStrategy {
    @Override public void sort(int[] arr) { /* quick sort */ }
}
class Sorter {
    private SortStrategy strategy;
    Sorter(SortStrategy s) { this.strategy = s; }
    void sort(int[] arr) { strategy.sort(arr); }
}