[Java Backend Zero to Hello] BÀI 2.10: ENUM & NESTED CLASS
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 2: Java Core Nâng Cao | Bài 25/86
BÀI 2.10: ENUM & NESTED CLASS
Mục tiêu
- Sử dụng Enum nâng cao
- Phân biệt các loại Nested Class
- Áp dụng Inner Class, Anonymous Class
- Hiểu về Local Class
1. ENUM CƠ BẢN
Enum là kiểu dữ liệu đặc biệt để định nghĩa tập hợp hằng số cố định.
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Day today = Day.MONDAY;
2. ENUM NÂNG CAO
2.1 Enum với thuộc tính và method
public enum OrderStatus {
PENDING("Đang chờ"),
CONFIRMED("Đã xác nhận"),
SHIPPING("Đang giao"),
DELIVERED("Đã giao"),
CANCELLED("Đã hủy");
private final String displayName;
OrderStatus(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
2.2 Enum với method trừu tượng
public enum Operation {
PLUS {
@Override
public double apply(double x, double y) {
return x + y;
}
},
MINUS {
@Override
public double apply(double x, double y) {
return x - y;
}
},
MULTIPLY {
@Override
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
@Override
public double apply(double x, double y) {
return x / y;
}
};
public abstract double apply(double x, double y);
}
double result = Operation.PLUS.apply(5, 3); // 8
2.3 Các method hữu ích
// values() - tất cả giá trị
OrderStatus[] all = OrderStatus.values();
// valueOf() - tìm theo tên
OrderStatus status = OrderStatus.valueOf("PENDING");
// name() - tên
String name = OrderStatus.PENDING.name(); // "PENDING"
// ordinal() - vị trí
int ordinal = OrderStatus.PENDING.ordinal(); // 0
2.4 EnumSet và EnumMap
// EnumSet - Set hiệu quả cho enum
EnumSet<OrderStatus> activeStatuses = EnumSet.of(
OrderStatus.PENDING, OrderStatus.CONFIRMED
);
// EnumMap - Map hiệu quả cho enum key
EnumMap<OrderStatus, String> statusMessages = new EnumMap<>(OrderStatus.class);
statusMessages.put(OrderStatus.PENDING, "Đang xử lý");
3. NESTED CLASS
Class được khai báo bên trong class khác.
3.1 Static Nested Class
public class Outer {
private static int outerStatic = 10;
private int outerInstance = 20;
public static class StaticNested {
public void display() {
System.out.println("Outer static: " + outerStatic);
// System.out.println(outerInstance); // ❌ Không truy cập được
}
}
}
// Sử dụng
Outer.StaticNested nested = new Outer.StaticNested();
nested.display();
3.2 Inner Class (Non-static Nested)
public class Outer {
private int outerInstance = 20;
public class Inner {
public void display() {
System.out.println("Outer instance: " + outerInstance); // ✅ Truy cập được
}
}
}
// Sử dụng - cần instance của Outer
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display();
3.3 Local Class
Class khai báo trong method.
public void process() {
final int localVar = 10;
class LocalClass {
public void display() {
System.out.println("Local var: " + localVar);
}
}
LocalClass obj = new LocalClass();
obj.display();
}
3.4 Anonymous Class
Class không tên, dùng để implement interface hoặc extend class ngay tại chỗ.
// Implement interface
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous runnable");
}
};
// Extend class
Animal animal = new Animal() {
@Override
public void makeSound() {
System.out.println("Anonymous sound");
}
};
💡 Trong Java 8+, thường dùng Lambda thay Anonymous Class cho Functional Interface.
4. SO SÁNH CÁC LOẠI NESTED CLASS
| Loại | Truy cập Outer | Khai báo | Khi nào dùng |
|---|---|---|---|
| Static Nested | Chỉ static | Trong class | Helper class, không cần outer instance |
| Inner | Cả static và instance | Trong class | Cần truy cập instance của outer |
| Local | Cả hai | Trong method | Chỉ dùng trong method |
| Anonymous | Cả hai | Tại chỗ | Implement nhanh (nên thay bằng Lambda) |
5. VÍ DỤ THỰC TẾ
5.1 Builder Pattern với Static Nested
public class User {
private final String name;
private final String email;
private final int age;
private User(Builder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
}
public static class Builder {
private String name;
private String email;
private int age;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(this);
}
}
}
// Sử dụng
User user = new User.Builder()
.name("An")
.email("an@example.com")
.age(25)
.build();
5.2 LinkedList với Inner Class
public class LinkedList<T> {
private Node head;
private int size;
private class Node {
T data;
Node next;
Node(T data) {
this.data = data;
}
}
public void add(T data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
} else {
Node current = head;
while (current.next != null) {
current = current.next;
}
current.next = newNode;
}
size++;
}
}
6. BÀI TẬP THỰC HÀNH
Bài 1: Enum với logic
public enum PaymentMethod {
CASH {
@Override
public double calculateFee(double amount) {
return 0;
}
},
CREDIT_CARD {
@Override
public double calculateFee(double amount) {
return amount * 0.02;
}
},
BANK_TRANSFER {
@Override
public double calculateFee(double amount) {
return 5000;
}
};
public abstract double calculateFee(double amount);
}
Bài 2: Enum với thuộc tính
public enum HttpStatus {
OK(200, "Thành công"),
BAD_REQUEST(400, "Yêu cầu không hợp lệ"),
NOT_FOUND(404, "Không tìm thấy"),
INTERNAL_SERVER_ERROR(500, "Lỗi server");
private final int code;
private final String message;
HttpStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() { return code; }
public String getMessage() { return message; }
public static HttpStatus fromCode(int code) {
for (HttpStatus status : values()) {
if (status.code == code) return status;
}
throw new IllegalArgumentException("Unknown code: " + code);
}
}
Bài 3: Static Nested cho Repository
public class UserRepository {
private final Map<Long, User> users = new HashMap<>();
public void save(User user) {
users.put(user.getId(), user);
}
public Optional<User> findById(Long id) {
return Optional.ofNullable(users.get(id));
}
// Static nested class cho query builder
public static class QueryBuilder {
private String namePattern;
private Integer minAge;
public QueryBuilder nameLike(String pattern) {
this.namePattern = pattern;
return this;
}
public QueryBuilder minAge(int age) {
this.minAge = age;
return this;
}
public List<User> execute() {
// Logic query
return new ArrayList<>();
}
}
}
7. TÓM TẮT
| Khái niệm | Mô tả |
|---|---|
| Enum | Tập hợp hằng số có kiểu |
| Enum method | Có thể có method, field |
| Enum abstract | Mỗi giá trị override method |
| Static Nested | Class tĩnh trong class |
| Inner Class | Class không tĩnh, cần outer instance |
| Local Class | Class trong method |
| Anonymous Class | Class không tên |
Bài tiếp theo: 2.11 Java 9-17 features
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 2.9: ANNOTATION & REFLECTION
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 2.11: JAVA 9-17 FEATURES
All rights reserved