JavaRush /Java Blog /Random-KO /커피 브레이크 #143. Java 17의 봉인된 클래스. 싱글톤을 구현하는 4가지 방법

커피 브레이크 #143. Java 17의 봉인된 클래스. 싱글톤을 구현하는 4가지 방법

Random-KO 그룹에 게시되었습니다

Java 17의 봉인된 클래스

출처: Codippa 이번 포스팅에서는 Java 17에 도입된 새로운 기능인 Sealed 클래스와 이를 선언하고 사용하는 방법을 예제와 함께 살펴보겠습니다. 커피 브레이크 #143.  Java 17의 봉인된 클래스. 싱글톤을 구현하는 4가지 방법 - 1봉인된 클래스는 Java 15에서 미리 보기 기능으로 처음 등장했고 나중에 Java 16에서도 동일한 상태로 나타났습니다. 이 기능은 Java 17( JEP 409 ) 릴리스에서 완전히 작동하게 되었습니다 .

봉인 수업이란 무엇입니까?

봉인 클래스를 사용하면 하위 클래스를 제한하거나 선택할 수 있습니다. 클래스는 상위 클래스의 허용된 하위 클래스 목록에 없는 경우 비공개 클래스를 확장할 수 없습니다. 클래스는 sealing 키워드를 사용하여 봉인됩니다 . Sealed 클래스 뒤에는 이를 확장할 수 있는 클래스 목록과 함께 allowed 키워드가 와야 합니다. 예는 다음과 같습니다.
public sealed class Device permits Computer, Mobile {
}
이 선언은 Device 가 ComputerMobile 클래스 에 의해서만 확장될 수 있음을 의미합니다 . 다른 클래스가 이를 확장하려고 하면 컴파일러 오류가 발생합니다. 봉인 클래스를 확장하는 클래스의 선언에는 final , 봉인 되지 않은 키워드 가 있어야 합니다 . 따라서 우리는 고정된 클래스 계층 구조를 갖습니다. 이것이 하위 클래스를 생성하는 것과 어떤 관련이 있나요?
  1. 최종은 더 이상 하위 분류될 수 없음을 의미합니다.

  2. sealing 은 허가를 받아 하위 클래스를 선언해야 함을 의미합니다 .

  3. 봉인되지 않았다는 것은 여기서 부모-자식 계층 구조가 종료됨을 의미합니다 .

예를 들어 컴퓨터는 노트북 자체가 봉인되지 않은 상태로 유지되는 한 노트북데스크톱 클래스를 허용합니다 . 이는 노트북이 Apple , Dell , HP 등과 같은 등급으로 확장될 수 있음을 의미합니다.

봉인 클래스 도입의 주요 목표는 다음과 같습니다.

  1. 지금까지는 final 키워드 를 사용하여 클래스 확장만 제한할 수 있었습니다 . 봉인된 클래스는 허용 목록에 포함하여 확장할 수 있는 클래스를 제어합니다.

  2. 또한 클래스는 그 중 어느 클래스가 자식 클래스가 될지 제어할 수 있습니다.

규칙

Sealed 클래스를 사용할 때 기억해야 할 몇 가지 규칙은 다음과 같습니다.
  1. 봉인 클래스는 허가를 사용하여 확장할 수 있는 클래스를 정의해야 합니다 . 하위 클래스가 상위 클래스 내에 내부 클래스로 정의된 경우 이는 필요하지 않습니다.

  2. 하위 클래스는 final , sealing 또는 non-sealed 이어야 합니다 .

  3. 허용된 하위 클래스는 상위 봉인 클래스를 확장해야 합니다.

    즉, 봉인된 클래스 A가 클래스 B를 허용하는 경우 B는 A를 확장해야 합니다.

  4. 봉인된 클래스가 모듈에 있는 경우 하위 클래스도 동일한 모듈에 있어야 하며, 상위 봉인된 클래스가 명명되지 않은 모듈에 있는 경우 동일한 패키지에 있어야 합니다.

  5. 직접 허용된 클래스만 봉인 클래스를 확장할 수 있습니다. 즉, A가 B의 확장을 허용하는 봉인된 클래스라면 B도 C를 허용하는 봉인된 클래스입니다.

    그러면 C는 B만 확장할 수 있지만 A를 직접 확장할 수는 없습니다.

봉인된 인터페이스

봉인된 클래스와 마찬가지로 인터페이스도 봉인될 수 있습니다. 이러한 인터페이스에서는 하위 인터페이스나 클래스를 선택할 수 있으며, 허가를 사용하여 확장할 수 있습니다 . 좋은 예는 다음과 같습니다.
public sealed interface Device permits Electronic, Physical,
DeviceImpl {
}
여기서 Device 인터페이스를 사용하면 전자물리적 인터페이스가 이를 확장하고 후속 구현을 위해 DeviceImpl 클래스를 확장 할 수 있습니다 .

봉인된 기록

Sealed 클래스 는 Java 16에 도입된 항목과 함께 사용할 수 있습니다. 항목은 일반 클래스를 확장할 수 없으므로 비공개 인터페이스만 구현할 수 있습니다. 또한 표기법은 final 을 의미합니다 . 따라서 하위 클래스로 분류할 수 없기 때문에 항목은 allowed 키워드를 사용할 수 없습니다 . 즉, 레코드가 포함된 단일 수준 계층 구조만 있습니다. 예는 다음과 같습니다.
public sealed interface Device permits Laptop {
}
public record Laptop(String brand) implement Device {
}

반사 지원

Java Reflection은 봉인된 클래스에 대한 지원을 제공합니다. java.lang.Class 에 다음 두 가지 메소드가 추가되었습니다 .

1. getPermittedSubclasses()

이는 이 클래스 객체가 허용하는 모든 클래스를 포함하는 java.lang.Class 배열을 반환합니다 . 예:
Device c = new Device();
Class<? extends Device> cz = c.getClass();
Class<?>[] permittedSubclasses = cz.getPermittedSubclasses();
for (Class<?> sc : permittedSubclasses){
  System.out.println(sc.getName());
}
결론:
컴퓨터 모바일

2.실드됨()

호출되는 클래스나 인터페이스가 봉인된 경우 true를 반환합니다 . 지금은 Java 17에 추가된 봉인 클래스에 대한 모든 것입니다. 이 기사가 유익한 정보가 되었기를 바랍니다.

싱글톤을 구현하는 4가지 방법

출처: Medium 오늘은 싱글톤 디자인 패턴을 구현하는 여러 가지 방법을 배우겠습니다. 싱글톤 디자인 패턴은 Java 프로젝트에서 널리 사용됩니다. 소켓이나 데이터베이스 연결과 같은 리소스에 대한 액세스 제어를 제공합니다. 한번은 대규모 칩 회사의 웹 개발자 자리에 대한 인터뷰에서 싱글톤을 구현해 달라는 요청을 받은 적이 있습니다. 웹 직위에 대한 면접은 이번이 처음이었고, 준비를 많이 하지 않았기 때문에 가장 어려운 솔루션인 지연 인스턴스화를 선택했습니다. 내 코드는 90%만 정확하고 효율적이지 않아서 최종 라운드에서 패배했습니다... 그래서 제 기사가 여러분에게 도움이 되기를 바랍니다.

초기 인스턴스화

class Singleton {
    private Singleton() {}
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
}
객체는 초기화 시 이미 생성되었으므로 여기에는 스레드 안전 문제가 없지만, 아무도 사용하지 않으면 메모리 리소스가 낭비됩니다.

게으른 구현

class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
지연 초기화 패턴을 사용하면 요청 시 개체가 생성됩니다. 그러나 이 방법에는 스레드 안전 문제가 있습니다. 두 스레드가 라인 5에서 동시에 시작되면 두 개의 싱글톤 인스턴스가 생성됩니다. 이를 방지하려면 잠금을 추가해야 합니다.
class Singleton {
    private Singleton() {}
    private static Singleton instance = null;

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
DCL(Double-Checked Locking): 6행에는 잠금이 없으므로 객체가 이미 생성된 경우 이 행은 매우 빠르게 작동합니다. 왜 인스턴스 == null 을 다시 확인해야 합니까 ? 아마도 7행에 두 개의 스레드가 도입되었기 때문입니다. 첫 번째 스레드는 객체를 시작했고 두 번째 스레드는 Singleton.class lock 을 기다리고 있습니다 . 검사가 없으면 두 번째 스레드가 싱글톤 개체를 다시 생성합니다. 그러나 이 방법은 스레드에 여전히 위험합니다. 9행은 바이트 코드 세 줄로 나눌 수 있습니다.
  1. 메모리를 할당합니다.
  2. 개체를 초기화합니다.
  3. 인스턴스 참조에 객체를 할당합니다.
JVM이 순서대로 실행되지 않을 수 있으므로 가상 머신은 초기화 전에 인스턴스 참조에 개체를 할당할 수 있습니다. 다른 스레드는 이미 != null 인스턴스를 보고 이를 사용하기 시작하여 문제를 일으킬 것입니다. 따라서 인스턴스에 휘발성을 추가해야 하며 , 그러면 코드는 다음과 같습니다.
class Singleton {
    private Singleton() {}
    private volatile static Singleton instance = null;

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

정적 내부 클래스 사용

public class Singleton {
  private Singleton() {}
  private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
  }
  public static final Singleton getInstance() {
    return SingletonHolder.INSTANCE;
  }
}
SingletonHolder는 정적 내부 클래스이며 getInstance 메소드가 호출될 때만 초기화됩니다 . JVM의 init 클래스는 <clinit> cmd를 실행 하고 JVM 자체는 하나의 스레드만 대상 클래스에서 <clinit>를 호출할 수 있는지 확인하고 다른 스레드는 대기합니다.

싱글톤으로서의 열거형

public enum EnumSingleton {
    INSTANCE;
    int value;
    public int getValue() {
        return value;
    }
    public int setValue(int v) {
        this.value = v;
    }
}
기본적으로 열거형 인스턴스 는 스레드로부터 안전하므로 이중 확인 잠금에 대해 걱정할 필요가 없으며 작성하기가 매우 쉽습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION