Sealed 클래스 (Java 17+)
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 52번째.
전통적인 Java에서는 클래스를 생성할 때, (final로 표시하지 않는 한) 다른 어떤 클래스도 이를 상속할 수 있습니다. 하지만 상속을 허용하되, 아무나 상속받지 못하게 하고 싶다면 어떨까요? Java 17은 어떤 클래스가 자신의 클래스를 상속할 수 있는지 정밀하게 제어할 수 있도록 봉인된 클래스(sealed classes)를 도입했습니다.
봉인된 클래스(sealed class)는 sealed와 permits 키워드를 사용하여 허용된 하위 클래스를 명시적으로 선언합니다:
sealed class Shape permits Circle, Rectangle, Triangle {
abstract double area();
}
final class Circle extends Shape {
double radius;
double area() { return Math.PI * radius * radius; }
}
final class Rectangle extends Shape {
double width, height;
double area() { return width * height; }
}
final class Triangle extends Shape {
double base, height;
double area() { return 0.5 * base * height; }
}Circle, Rectangle, Triangle만이 Shape를 상속(extend)할 수 있습니다. 그 외의 다른 클래스가 이를 상속하려고 시도하면 컴파일 오류가 발생합니다.
허용된 각 하위 클래스는 세 가지 제어자 중 하나를 사용해야 합니다: final (더 이상 확장 불가), sealed (제한 체인을 계속 유지), 또는 non-sealed (제한 없는 확장을 허용):
sealed class Vehicle permits Car, Truck { }
final class Car extends Vehicle { } // 확장할 수 없음
non-sealed class Truck extends Vehicle { } // 누구나 Truck을 확장할 수 있음봉인된 클래스(Sealed classes)는 컴파일러가 모든 가능한 하위 타입을 알고 있으며 망라성(exhaustiveness)을 검증할 수 있기 때문에, switch 표현식의 패턴 매칭과 함께 사용할 때 특히 강력합니다. 결제 수단, 응답 타입 또는 기하학적 도형과 같이 도메인 내의 고정된 타입 집합을 모델링할 때 이상적입니다.
챌린지
쉬움애플리케이션에서 존재할 수 있는 알림 유형을 제한함으로써 봉인된 클래스(sealed classes)를 보여주는 알림 시스템을 구축해 보겠습니다. 특정 알림 유형만 허용되고 각 유형이 전달을 다르게 처리하는 계층 구조를 만들 것입니다.
코드는 다음 네 개의 파일로 구성됩니다:
Notification.java: 모든 알림의 기반이 되는 봉인된 추상 클래스(sealed abstract class)를 생성합니다. 이 클래스는 정확히 세 개의 서브클래스인EmailNotification,SMSNotification,PushNotification만을 허용(permit)해야 합니다. 이 봉인된 클래스에는 보호된 필드인message(String), 이를 초기화하는 생성자, 메시지에 대한 getter, 그리고 알림이 전송되는 방식을 설명하는 String을 반환하는 추상 메서드deliver()가 필요합니다.EmailNotification.java: Notification을 상속받는final클래스를 생성합니다. EmailNotification은 이메일 주소를 위한 추가적인 프라이빗 필드recipient(String)를 가집니다. 생성자는 메시지와 수신자(recipient)를 모두 매개변수로 받아야 하며,super()를 사용하여 부모 생성자를 호출해야 합니다.deliver()메서드는"Sending email to " + recipient + ": " + message를 반환해야 합니다.SMSNotification.java: Notification을 상속받는non-sealed클래스를 생성합니다. 이는 나중에 필요한 경우 다른 클래스가 이를 상속받을 수 있도록 허용합니다. SMSNotification은 추가적인 프라이빗 필드phoneNumber(String)를 가집니다. 생성자는 메시지와 전화번호를 매개변수로 받습니다.deliver()메서드는"Sending SMS to " + phoneNumber + ": " + message를 반환해야 합니다.PushNotification.java: Notification을 상속받는final클래스를 생성합니다. PushNotification은 추가적인 프라이빗 필드deviceId(String)를 가집니다. 생성자는 메시지와 기기 ID(device ID)를 매개변수로 받습니다.deliver()메서드는"Sending push to device " + deviceId + ": " + message를 반환해야 합니다.Main.java: 알림 시스템을 하나로 합칩니다! 메시지(String), 이메일 주소(String), 전화번호(String), 기기 ID(String)의 네 가지 입력을 받게 됩니다.동일한 메시지를 사용하되 각각의 연락처 정보를 사용하여 각 알림 유형의 인스턴스를 하나씩 생성합니다. 봉인된 클래스의 다형성을 보여주기 위해 세 가지 알림을 모두
Notification[]타입의 배열에 저장합니다. 그런 다음 배열을 순회하며 각 알림에 대해deliver()를 호출한 결과를 출력합니다.
메시지, 이메일 주소, 전화번호, 기기 ID 순서대로 네 개의 입력을 받게 됩니다.
봉인된 클래스가 계층 구조를 어떻게 제한하는지 확인해 보세요. 허용된 세 개의 클래스만 Notification을 상속받을 수 있습니다. 각 서브클래스는 반드시 final, sealed, 또는 non-sealed로 선언되어야 합니다. 이를 통해 다형성을 활용하면서도 타입 계층 구조를 완벽하게 제어할 수 있습니다!
치트 시트
봉인된 클래스(sealed class)는 sealed와 permits 키워드를 사용하여 어떤 클래스가 이를 상속할 수 있는지 제한합니다:
sealed class Shape permits Circle, Rectangle, Triangle {
abstract double area();
}permits에 나열된 클래스들만 봉인된 클래스를 상속할 수 있습니다. 그 외의 클래스가 상속을 시도하면 컴파일 오류가 발생합니다.
허용된 각 서브클래스는 다음 세 가지 제어자 중 하나를 사용해야 합니다:
final- 더 이상의 상속을 방지합니다sealed- 자체적인 허용 서브클래스 목록을 통해 제한 체인을 유지합니다non-sealed- 제한 없는 상속이 가능하도록 계층 구조를 엽니다
sealed class Vehicle permits Car, Truck { }
final class Car extends Vehicle { } // 상속될 수 없음
non-sealed class Truck extends Vehicle { } // 누구나 Truck을 상속할 수 있음봉인된 클래스는 결제 수단, 응답 유형 또는 기하학적 도형과 같이 도메인 내의 고정된 타입 집합을 모델링하는 데 유용합니다. 컴파일러가 가능한 모든 서브타입을 알고 있기 때문에 switch 표현식의 패턴 매칭과 함께 사용하기 좋습니다.
직접 해보기
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 네 개의 입력을 읽습니다
String message = scanner.nextLine();
String email = scanner.nextLine();
String phoneNumber = scanner.nextLine();
String deviceId = scanner.nextLine();
// TODO: 동일한 message를 사용하여 각 알림 유형별로 하나씩 생성하세요
// - message와 email을 사용하는 EmailNotification
// - message와 phoneNumber를 사용하는 SMSNotification
// - message와 deviceId를 사용하는 PushNotification
// TODO: 세 가지 알림을 모두 Notification[] 배열에 저장하세요
// 이것은 sealed 클래스를 사용한 다형성을 보여줍니다
// TODO: 배열을 반복하며 각 알림에 대해 deliver()의 결과를 출력하세요
// 각 알림에 대하여
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조