sealed class
Java 15에서 도입된 새로운 기능으로, 클래스나 인터페이스가 상속될 때 어떤 클래스나 인터페이스가 상속을 받을 수 있는지 명시적으로 제한할 수 있습니다. 즉, 상속 계층을 더 명확하고 제어 가능하게 만드는 기능입니다.
sealed를 통해 명시적으로 상속 구조를 제어하고 패턴 매칭시에도 편리하게 사용 가능합니다.
기본 키워드
- Sealed Class는 sealed 키워드를 사용하여 선언됩니다.
- Permits: Sealed 클래스는 permits 키워드를 사용하여 어떤 클래스가 이 클래스를 상속할 수 있는지 지정합니다. 상속할 수 있는 클래스는 반드시 같은 모듈이나 패키지 내에 있어야 합니다.
- Final, Non-Sealed, Abstract: Sealed 클래스를 상속받은 클래스는 세 가지 옵션 중 하나를 선택해야 합니다:
- Final: 해당 클래스는 더 이상 상속될 수 없습니다.
- Non-Sealed: 해당 클래스는 봉인(sealed)을 해제하여 다른 클래스가 이 클래스를 상속받을 수 있게 만듭니다.
public abstract sealed class Shape permits Circle, Square, Triangle {}
public final class Circle extends Shape {
// Circle은 더 이상 상속될 수 없음
}
public non-sealed class Square extends Shape {
// Square는 다른 클래스가 상속할 수 있음
}
public final class Triangle extends Shape {
// Triangle은 더 이상 상속될 수 없음
}
// 불가능
public class Pentagon extends Shape {
// Pentagon은 다른 클래스가 상속할 수 없음
}
// 불가능
public class Hexagon extends Circle {
// Hexagon은 다른 클래스가 상속할 수 없음
}
// 가능
public class Rectangle extends Square {
// Rectangle은 다른 클래스가 상속할 수 없음
}
패턴 매칭 이용 예시
static void processShape(Shape shape) {
switch (shape) {
case Circle c -> System.out.println("Circle");
case Square s -> System.out.println("Square");
case Triangle t -> System.out.println("Triangle");
}
}
Hidden classes
동적으로 생성된 클래스를 외부 코드에서 숨기고, 이 클래스들이 오직 정의된 클래스 로더의 컨텍스트 내에서만 사용되도록 하는 기능입니다. Hidden Classes는 동적 언어 런타임, 프레임워크, 또는 바이트코드를 직접 조작하는 라이브러리들이 더 안전하고 효율적으로 클래스를 처리할 수 있도록 도와줍니다. 이 클래스들은 외부 코드에서 접근하거나 참조할 수 없으며, 메모리에서 안전하게 제거할 수 있는 장점이 있습니다.
일반적인 개발을 진행하면서 사용할 일은 없을 듯
Hidden Classes의 주요 특징
- 클래스 로더에서 숨겨짐:
- Hidden Classes는 클래스 로더가 로드하더라도 외부 코드에서는 접근할 수 없습니다. 즉, 이 클래스들은 특정 클래스 로더 내부에서만 사용 가능하며, 해당 클래스 로더가 외부에서 탐색하거나 직접적으로 접근할 수 없습니다.
- 동적 클래스 생성:
- 주로 프레임워크나 동적 언어 런타임에서 런타임 중에 클래스 바이트코드를 생성할 때 유용합니다. 이는 JVM 내에서 빠르게 동적으로 클래스를 생성하고 삭제할 수 있도록 도와줍니다.
- GC(가비지 컬렉션)에 의한 메모리 해제:
- Hidden Classes는 더 이상 참조되지 않을 때 **GC(가비지 컬렉션)**에 의해 메모리에서 자동으로 해제됩니다. 이 클래스는 사용이 끝나면 안전하게 삭제되며, 애플리케이션의 메모리 관리를 더 효율적으로 할 수 있습니다.
- 상속과 인터페이스 구현:
- Hidden Classes는 다른 클래스나 인터페이스를 구현할 수 있습니다. 따라서 동적으로 생성된 클래스가 기존의 클래스 구조와 일치하는 방식으로 사용될 수 있습니다.
- Lookup API 통합:
- Hidden Classes는 MethodHandles.Lookup API를 사용해 정의됩니다. 이 API를 통해 런타임 시 동적으로 생성된 클래스에 대한 제어를 수행할 수 있습니다.
- 이 예제는 바이트코드로부터 Hidden Class를 정의하는 예입니다. defineHiddenClass 메서드는 이 클래스를 외부 코드에서 접근할 수 없도록 숨기고, 런타임 중에만 사용할 수 있게 합니다.
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class<?> hiddenClass = lookup.defineHiddenClass(bytes, true, MethodHandles.Lookup.ClassOption.NESTMATE).lookupClass();
Hidden Classes의 주요 사용 사례
- 프레임워크:
- 프레임워크에서 런타임 중에 클래스를 생성할 때, Hidden Classes는 해당 클래스를 숨기고 외부로 노출되지 않도록 하여 안전성을 유지합니다. 예를 들어, 바이트코드 조작 라이브러리(CGLIB, ASM 등)에서 동적으로 클래스를 생성할 때 유용합니다.
- 동적 언어 런타임:
- Java 기반의 동적 언어(예: Groovy, Kotlin) 런타임에서 사용될 수 있으며, 스크립트 언어가 동적으로 클래스를 생성할 때 이 클래스를 숨김으로써 자바 애플리케이션의 안정성을 높일 수 있습니다.
- 클래스 인스턴스화 제한:
- 특정 클래스가 외부에서 사용되지 않고 프레임워크나 라이브러리 내부에서만 인스턴스화되어야 할 경우, Hidden Classes를 사용해 해당 클래스를 안전하게 정의할 수 있습니다.
Hidden Classes의 장점
- 보안성 강화: Hidden Classes는 외부로부터 숨겨져 있으므로 외부 코드에서 참조하거나 조작할 수 없습니다. 이는 보안이 중요한 애플리케이션에서 유용하게 사용됩니다.
- 동적 클래스 로딩: JVM 내에서 런타임 중에 빠르게 클래스를 정의하고 삭제할 수 있어, 프레임워크나 동적 언어 런타임에서 매우 효율적으로 사용될 수 있습니다.
- 메모리 관리: GC가 동적으로 생성된 클래스를 처리할 수 있으므로, 더 이상 사용되지 않는 클래스는 자동으로 메모리에서 해제됩니다.
댓글