Java Interfaces, Polymorphism, Lambda, Inner Classes, Enums, Annotations, and Wrapper Classes

  1. Interfaces

An interface in Java is a contract that defines a set of abstract behaviors. It enables decoupling and polymorphism without forcing a rigid inheritance hierarchy.

1.1 Refactoring a Student Management System with Interfaces

Replacing a fixed-length array with ArrayList removes the need for manual resizing. The steps:

  1. Create a new repository class StudentRepoList backed by ArrayList<Student>.
  2. Ensure its public API matches the original StudentRepoArray sothat StudentService remains unchanged.
  3. Delegate all CRUD operations to ArrayList.
public class StudentRepoList implements StudentRepository {
    private final List<Student> store = new ArrayList<>();

    @Override
    public boolean add(Student s) { return store.add(s); }

    @Override
    public List<Student> findAll() { return new ArrayList<>(store); }

    @Override
    public void delete(String id) { store.removeIf(stu -> stu.getId().equals(id)); }

    @Override
    public void update(String id, Student newData) {
        int idx = IntStream.range(0, store.size())
                           .filter(i -> store.get(i).getId().equals(id))
                           .findFirst()
                           .orElse(-1);
        if (idx != -1) store.set(idx, newData);
    }
}

1.2 Extracting an Interface

Define StudentRepository as an interface and let both array-based and list-based implementations adhere to it:

public interface StudentRepository {
    boolean add(Student s);
    List<Student> findAll();
    void delete(String id);
    void update(String id, Student newData);
}

1.3 Interface Characteristics

  • Declared with interface keyword.
  • Cannot be instantiated; used via implementing clases.
  • All fields are public static final; all methods (pre-Java 8) are public abstract.

1.4 Interface Evolution (Java 8+)

  • Default methods provide concrete implementations without breaking existing implementers.
  • Static methods belong to the interface itself and cannot be overridden.
  • Private methods (Java 9+) allow code reuse within interface internals.
  1. Polymorphism

Polymorphism allows a single variable of a supertype to reference objects of multiple subtypes, selecting the correct overridden behavior at runtime.

2.1 Prerequisites

  1. Inheritance or interface implementation.
  2. Method overriding.
  3. Supertype reference pointing to subtype instance.

2.2 Member Access Rules

Member Compile-time Run-time
Field Supertype Supertype
Method Supertype Subtype (dynamic dispatch)

2.3 Casting & instanceof

Animal a = new Dog();
if (a instanceof Dog d) {
    d.bark();
}
  1. Inner Classes

Java allows nesting classes for tighter encapsulation and logical grouping.

3.1 Member Inner Class

public class Outer {
    private int secret = 42;
    public class Inner {
        public void reveal() { System.out.println(secret); }
    }
}

Instantiation: Outer.Inner in = new Outer().new Inner();

3.2 Static Nested Class

Does not hold an implicit reference to the outer instance.

Outer.Nested n = new Outer.Nested();

3.3 Local & Anonymous Classes

public void process() {
    class Local { /* … */ }
    Runnable r = new Runnable() {
        public void run() { /* … */ }
    };
}
  1. Lambda Expressions

Lambdas provide a concise way to represent functional-interface instances.

4.1 Syntax

(params) -> expression
(params) -> { statements; }

4.2 Examples

BinaryOperator<Integer> add = (x, y) -> x + y;
Consumer<String> print = s -> System.out.println(s);

4.3 Requirements

  • Target type must be a functional interface (exactly one abstract method).
  • Type inference allows omitting parameter types.
  1. Enums

Enums model fixed sets of constants with type safety.

5.1 Basic Enum

public enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }

5.2 Rich Enum with Fields & Behavior

public enum Planet {
    EARTH(5.97, 6371),
    MARS(0.642, 3389);

    private final double mass; // kg
    private final double radius; // km
    Planet(double m, double r) { mass = m; radius = r; }
    public double surfaceGravity() { return 6.67E-11 * mass / (radius * radius); }
}

5.3 Enum Implements Interface

public enum Operation implements IntBinaryOperator {
    PLUS  { public int applyAsInt(int a, int b) { return a + b; } },
    MINUS { public int applyAsInt(int a, int b) { return a - b; } }
}
  1. Annotations

Annotations supply metadata that can be processed at compile-time or run-time.

6.1 Built-in Annotations

  • @Override – ensures method overrides.
  • @Deprecated – marks obsolete elements.
  • @SuppressWarnings – disables compiler warnings.

6.2 Custom Annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Entity {
    String table() default "";
}

6.3 JUnit 5 Quick Start

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CalcTest {
    @Test
    void addsTwoNumbers() {
        assertEquals(4, 2 + 2);
    }
}
  1. Wrapper Classes

Each primitive has an immutable wrapper: Integer, Double, etc.

7.1 Boxing & Unboxing

Integer boxed = 5;        // autoboxing
int primitive = boxed;    // auto-unboxing

7.2 Utility APIs

int max = Integer.MAX_VALUE;
String hex = Integer.toHexString(255);
int val = Integer.parseInt("42");

7.3 Cache Behavior

Integer a = 100, b = 100; // same cached object
Integer x = 1000, y = 1000; // different objects
  1. Quick Exercises

  1. Write an anonymous subclass of Object that prints Hello, Lambda! when its greet() method is invoked.
  2. Create an enum Priority with levels LOW, MEDIUM, HIGH and a method int getExpectedDays() returning 5, 3, 1 respectively.
  3. Implement a functional interface StringProcessor and use a lambda to reverse any input string.

Tags: java Interface Polymorphism lambda inner-class

Posted on Sun, 20 Sep 2026 16:17:58 +0000 by foreverdita