Lab 06: OOP — Classes & Encapsulation
Objective
Design and implement Java classes with fields, constructors, methods, and proper encapsulation. Use access modifiers, getters/setters, this, static members, and records.
Background
Object-Oriented Programming is Java's core paradigm. Classes are blueprints; objects are instances. Encapsulation — hiding implementation details behind a public interface — makes code maintainable. Java 16+ records reduce boilerplate for pure data classes. Understanding class design is the foundation for everything from Android apps to enterprise Spring Boot services.
Time
40 minutes
Prerequisites
Lab 02 (Variables & Primitives)
Lab 05 (Control Flow)
Tools
Java 21 (Eclipse Temurin)
Docker image:
innozverse-java:latest
Lab Instructions
Step 1: Your First Class
💡
privatefields +publicmethods is encapsulation. External code can't directly modifybalance— it must go throughdeposit()/withdraw(), which enforce business rules. This is how you prevent invalid state:balancecan never go negative.
📸 Verified Output:
Step 2: Constructors & Constructor Chaining
💡
this(...)constructor chaining avoids duplicating initialization logic. The delegating constructor must callthis(...)as its first statement. Mark fieldsfinalwhen they shouldn't change after construction — the compiler enforces this.
📸 Verified Output:
Step 3: Static Members — Class-Level State
💡
staticbelongs to the class, not instances.totalCreatedincrements every timenew Counter()is called, regardless of which instance you're looking at. Static factory methods (of()) are preferred over constructors when: the name conveys meaning, you want to return cached instances, or the return type might differ.
📸 Verified Output:
Step 4: Records — Immutable Data Classes
💡 Records are perfect for DTOs, value objects, and API responses. They're immutable by default (all fields are
final). The compact constructor lets you add validation without rewriting the full constructor. Use records instead of Lombok's@Datain modern Java.
📸 Verified Output:
Step 5: equals, hashCode & toString
💡 The
equals/hashCodecontract: ifa.equals(b)thena.hashCode() == b.hashCode(). Breaking this contract silently breaksHashMap,HashSet, andHashTable. UseObjects.equals()(null-safe) andObjects.hash()to implement correctly.
📸 Verified Output:
Step 6: Inner Classes & Nested Types
💡 The Builder pattern solves the "telescoping constructor" problem — instead of 5 constructors with different parameter combinations, you chain method calls and call
build(). It also makes construction self-documenting:.host("...").port(443).ssl(true)reads like configuration, not a mystery list of arguments.
📸 Verified Output:
Step 7: Object Lifecycle & Garbage Collection
💡 Java's Garbage Collector reclaims memory automatically when objects have no more references. You can't force GC (
System.gc()is a suggestion). For resource cleanup (files, DB connections, sockets), usetry-with-resourceswithAutoCloseable— the JVM guaranteesclose()is called.
📸 Verified Output:
Step 8: Complete Class — Shopping Cart
💡
ifPresentOrElseon Optional handles both "found" and "not found" in one readable expression. Combining records, streams, and switch expressions shows how modern Java is concise and expressive without external libraries.
📸 Verified Output:
Verification
Summary
You've built complete Java classes with encapsulation, constructor chaining, static members, records, equals/hashCode, builders, and the shopping cart capstone. These patterns are the daily vocabulary of Java development.
Further Reading
Last updated
