JavaRush /Java-Blog /Random-DE /Kaffeepause Nr. 143. Versiegelte Klassen in Java 17. 4 Mö...

Kaffeepause Nr. 143. Versiegelte Klassen in Java 17. 4 Möglichkeiten zur Implementierung von Singleton

Veröffentlicht in der Gruppe Random-DE

Versiegelte Klassen in Java 17

Quelle: Codippa In diesem Beitrag werden wir uns mit versiegelten Klassen befassen, einer neuen Funktion, die in Java 17 eingeführt wurde, und wie man sie anhand von Beispielen deklariert und verwendet. Kaffeepause Nr. 143.  Versiegelte Klassen in Java 17. 4 Möglichkeiten zur Implementierung von Singleton – 1Versiegelte Klassen erschienen zuerst in Java 15 als Vorschaufunktion und später in Java 16 mit demselben Status. Diese Funktion wurde mit der Veröffentlichung von Java 17 ( JEP 409 ) voll funktionsfähig .

Was sind versiegelte Klassen?

Mit einer versiegelten Klasse können Sie Unterklassen einschränken oder auswählen. Eine Klasse kann eine private Klasse nur dann erweitern, wenn sie in der Liste der zulässigen untergeordneten Klassen der übergeordneten Klasse enthalten ist. Die Klasse wird mit dem Schlüsselwort „sealed“ versiegelt . Auf die versiegelte Klasse muss das Schlüsselwort „permits“ folgen, zusammen mit einer Liste von Klassen, die es erweitern können. Hier ist ein Beispiel:
public sealed class Device permits Computer, Mobile {
}
Diese Deklaration bedeutet, dass Device nur um die Klassen Computer und Mobile erweitert werden kann . Wenn eine andere Klasse versucht, sie zu erweitern, wird ein Compilerfehler ausgegeben. Eine Klasse, die eine versiegelte Klasse erweitert, muss in ihrer Deklaration das Schlüsselwort „ final “, „sealed “ oder „non-sealed“ enthalten . Somit haben wir eine feste Klassenhierarchie. Was hat das mit der Erstellung einer untergeordneten Klasse zu tun?
  1. final bedeutet, dass es nicht weiter in Unterklassen unterteilt werden kann.

  2. versiegelt bedeutet, dass wir untergeordnete Klassen mit Berechtigungen deklarieren müssen .

  3. Nicht versiegelt bedeutet, dass wir hier die Eltern-Kind- Hierarchie beenden .

Beispielsweise erlaubt „Computer“ die Klassen „Laptop“ und „Desktop“ , solange „ Laptop“ selbst unversiegelt bleibt . Dies bedeutet, dass Laptops um Klassen wie Apple , Dell , HP usw. erweitert werden können.

Die Hauptziele der Einführung versiegelter Klassen sind:

  1. Bisher konnte man die Erweiterung einer Klasse nur über das finale Schlüsselwort einschränken . Eine versiegelte Klasse steuert, welche Klassen sie erweitern können, indem sie in die Liste der zulässigen Klassen aufgenommen wird.

  2. Außerdem kann die Klasse steuern, welche davon ihre untergeordneten Klassen sein werden.

Regeln

Bei der Verwendung versiegelter Klassen sind einige Regeln zu beachten:
  1. Eine versiegelte Klasse muss Klassen definieren, die sie mithilfe von Berechtigungen erweitern können . Dies ist nicht erforderlich, wenn die untergeordneten Klassen innerhalb der übergeordneten Klasse als innere Klasse definiert sind.

  2. Die untergeordnete Klasse muss entweder „final“ , „sealed “ oder „non-sealed“ sein .

  3. Eine zulässige untergeordnete Klasse muss die versiegelte übergeordnete Klasse erweitern.

    Das heißt, wenn die versiegelte Klasse A Klasse B zulässt, muss B A erweitern.

  4. Wenn sich die versiegelte Klasse in einem Modul befindet, müssen sich die untergeordneten Klassen ebenfalls im selben Modul befinden, oder im selben Paket, wenn sich die versiegelte übergeordnete Klasse in einem unbenannten Modul befindet.

  5. Nur direkt zugelassene Klassen können eine versiegelte Klasse erweitern. Das heißt, wenn A eine versiegelte Klasse ist, die es B ermöglicht, sie zu erweitern, dann ist B auch eine versiegelte Klasse, die es C ermöglicht.

    Dann kann C nur B erweitern, A jedoch nicht direkt erweitern.

Versiegelte Schnittstellen

Wie versiegelte Klassen können auch Schnittstellen versiegelt werden. Eine solche Schnittstelle kann die Auswahl ihrer untergeordneten Schnittstellen oder Klassen ermöglichen, die sie mithilfe von Permits erweitern können . Hier ist ein gutes Beispiel:
public sealed interface Device permits Electronic, Physical,
DeviceImpl {
}
Hier ermöglicht die Device- Schnittstelle die Erweiterung durch die elektronischen und physikalischen Schnittstellen sowie die DeviceImpl- Klasse für die spätere Implementierung.

Versiegelte Aufzeichnungen

Versiegelte Klassen können mit in Java 16 eingeführten Einträgen verwendet werden. Ein Eintrag kann keine reguläre Klasse erweitern, daher kann er nur eine private Schnittstelle implementieren. Darüber hinaus impliziert die Notation final . Daher kann ein Eintrag das Schlüsselwort „permits“ nicht verwenden , da er nicht in Unterklassen unterteilt werden kann. Das heißt, es gibt nur eine einstufige Hierarchie mit Datensätzen. Hier ist ein Beispiel:
public sealed interface Device permits Laptop {
}
public record Laptop(String brand) implement Device {
}

Reflexionsunterstützung

Java Reflection bietet Unterstützung für versiegelte Klassen. Die folgenden zwei Methoden wurden zu java.lang.Class hinzugefügt :

1. getPermittedSubclasses()

Dies gibt ein Array java.lang.Class zurück , das alle von diesem Klassenobjekt zugelassenen Klassen enthält. Beispiel:
Device c = new Device();
Class<? extends Device> cz = c.getClass();
Class<?>[] permittedSubclasses = cz.getPermittedSubclasses();
for (Class<?> sc : permittedSubclasses){
  System.out.println(sc.getName());
}
Abschluss:
Computermobil

2.isSealed()

Dies gibt true zurück , wenn die Klasse oder Schnittstelle, in der es aufgerufen wird, versiegelt ist. Das ist vorerst alles über die versiegelten Klassen, die in Java 17 hinzugefügt wurden. Ich hoffe, dieser Artikel war informativ.

4 Möglichkeiten zur Implementierung von Singleton

Quelle: Medium Heute lernen Sie verschiedene Möglichkeiten kennen, das Singleton-Entwurfsmuster zu implementieren. Das Singleton-Entwurfsmuster wird häufig in Java-Projekten verwendet. Es bietet Zugriffskontrolle auf Ressourcen, z. B. einen Socket oder eine Datenbankverbindung. Während eines Vorstellungsgesprächs für eine Stelle als Webentwickler bei einem großen Chiphersteller wurde ich einmal gebeten, einen Singleton zu implementieren. Dies war mein erstes Vorstellungsgespräch für eine Stelle im Web, und ich habe mich nicht viel vorbereitet, also habe ich mich für die schwierigste Lösung entschieden: Lazy Instantiation. Mein Code war nur zu 90 % korrekt und nicht effizient genug, ich habe in der letzten Runde verloren ... Ich hoffe also, dass mein Artikel für Sie nützlich sein wird.

Frühe Instanziierung

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

    public static Singleton getInstance() {
        return instance;
    }
}
Da das Objekt bereits bei der Initialisierung erstellt wird, besteht hier kein Problem mit der Thread-Sicherheit, aber es verschwendet Speicherressourcen, wenn es niemand verwendet.

Faule Implementierung

class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
Bei Verwendung eines verzögerten Initialisierungsmusters wird das Objekt bei Bedarf erstellt. Diese Methode weist jedoch ein Thread-Sicherheitsproblem auf: Wenn zwei Threads gleichzeitig in Zeile 5 gestartet werden, erstellen sie zwei Singleton-Instanzen. Um dies zu vermeiden, müssen wir eine Sperre hinzufügen:
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;
    }
}
Double-Checked Locking (DCL): In Zeile 6 gibt es keine Sperre, daher funktioniert diese Zeile sehr schnell, wenn das Objekt bereits erstellt wurde. Warum müssen wir „instance == null“ noch einmal überprüfen ? Denn möglicherweise werden in Zeile 7 zwei Threads eingeführt: Der erste hat das Objekt initiiert, der zweite wartet auf die Singleton.class- Sperre . Erfolgt keine Prüfung, erstellt der zweite Thread das Singleton-Objekt erneut. Diese Methode ist jedoch immer noch gefährlich für Threads. Zeile 9 kann in drei Zeilen Bytecode unterteilt werden:
  1. Speicher zuweisen.
  2. Init-Objekt.
  3. Objekt einer Instanzreferenz zuweisen.
Da die JVM möglicherweise außer Betrieb ist, kann die virtuelle Maschine vor der Initialisierung ein Objekt einer Instanzreferenz zuweisen. Ein anderer Thread sieht die != null- Instanz bereits , er wird sie verwenden und ein Problem verursachen. Wir müssen der Instanz also volatile hinzufügen , dann sieht der Code so aus:
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;
    }
}

Verwendung einer statischen inneren Klasse

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 ist eine statische innere Klasse und wird nur initialisiert, wenn die getInstance- Methode aufgerufen wird . Die Init-Klasse in der JVM führt <clinit> cmd aus , dann stellt die JVM selbst sicher, dass nur ein Thread <clinit> für die Zielklasse aufrufen kann, andere Threads warten.

Enum als Singleton

public enum EnumSingleton {
    INSTANCE;
    int value;
    public int getValue() {
        return value;
    }
    public int setValue(int v) {
        this.value = v;
    }
}
Standardmäßig ist eine Enum -Instanz threadsicher, sodass Sie sich keine Gedanken über doppelt überprüfte Sperren machen müssen und das Schreiben relativ einfach ist.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION