- 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:
- Create a new repository class
StudentRepoListbacked byArrayList<Student>. - Ensure its public API matches the original
StudentRepoArraysothatStudentServiceremains unchanged. - 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
interfacekeyword. - Cannot be instantiated; used via implementing clases.
- All fields are
public static final; all methods (pre-Java 8) arepublic 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.
- 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
- Inheritance or interface implementation.
- Method overriding.
- 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();
}
- 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() { /* … */ }
};
}
- 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.
- 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; } }
}
- 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);
}
}
- 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
- Quick Exercises
- Write an anonymous subclass of
Objectthat printsHello, Lambda!when itsgreet()method is invoked. - Create an enum
Prioritywith levels LOW, MEDIUM, HIGH and a methodint getExpectedDays()returning 5, 3, 1 respectively. - Implement a functional interface
StringProcessorand use a lambda to reverse any input string.