JavaRush /Blog Java /Random-FR /Pause café #143. Classes scellées en Java 17. 4 façons d'...

Pause café #143. Classes scellées en Java 17. 4 façons d'implémenter Singleton

Publié dans le groupe Random-FR

Classes scellées en Java 17

Source : Codippa Dans cet article, nous examinerons les classes scellées, une nouvelle fonctionnalité introduite dans Java 17, et comment les déclarer et les utiliser avec des exemples. Pause café #143.  Classes scellées en Java 17. 4 façons d'implémenter Singleton - 1Les classes scellées sont apparues pour la première fois dans Java 15 en tant que fonctionnalité d'aperçu, puis dans Java 16 avec le même statut. Cette fonctionnalité est devenue entièrement fonctionnelle avec la sortie de Java 17 ( JEP 409 ).

Que sont les cours scellés ?

Une classe scellée vous permet de restreindre ou de sélectionner des sous-classes. Une classe ne peut pas étendre une classe privée à moins qu'elle ne figure dans la liste des classes enfants autorisées de la classe parent. La classe est scellée à l'aide du mot-clé scellé . La classe scellée doit être suivie du mot-clé permits , ainsi que d'une liste de classes pouvant l'étendre. Voici un exemple :
public sealed class Device permits Computer, Mobile {
}
Cette déclaration signifie que Device ne peut être étendu que par les classes Computer et Mobile . Si une autre classe tente de l’étendre, une erreur du compilateur sera générée. Une classe qui étend une classe scellée doit avoir le mot-clé final , scellé ou non-scellé dans sa déclaration . Nous avons donc une hiérarchie de classes fixe. Quel est le rapport avec la création d’une classe enfant ?
  1. final signifie qu'il ne peut pas être davantage sous-classé.

  2. scellé signifie que nous devons déclarer les classes d'enfants avec permis .

  3. non scellé signifie que nous mettons ici fin à la hiérarchie parent-enfant .

Par exemple, Computer autorise les classes Laptop et Desktop tant que Laptop lui-même reste non scellé . Cela signifie que les ordinateurs portables peuvent être étendus à des classes telles que Apple , Dell , HP, etc.

Les principaux objectifs de l’introduction des classes scellées sont :

  1. Jusqu'à présent, vous ne pouviez limiter l'extension d'une classe qu'à l'aide du mot-clé final . Une classe scellée contrôle quelles classes peuvent l'étendre en les incluant dans la liste autorisée.

  2. Cela permet également à la classe de contrôler lesquelles d’entre elles seront ses classes enfants.

Règles

Quelques règles à retenir lors de l'utilisation de classes scellées :
  1. Une classe scellée doit définir des classes qui peuvent l'étendre à l'aide de permits . Cela n'est pas obligatoire si les classes enfants sont définies dans la classe parent en tant que classe interne.

  2. La classe enfant doit être soit finale , soit scellée soit non scellée .

  3. Une classe enfant autorisée doit étendre sa classe scellée parent.

    Autrement dit, si la classe scellée A autorise la classe B, alors B doit étendre A.

  4. Si la classe scellée se trouve dans un module, alors les classes enfants doivent également se trouver dans le même module, ou dans le même package si la classe scellée parent se trouve dans un module sans nom.

  5. Seules les classes directement autorisées peuvent étendre une classe scellée. Autrement dit, si A est une classe scellée qui permet à B de l'étendre, alors B est également une classe scellée qui permet à C.

    Alors C ne peut étendre que B, mais ne peut pas étendre directement A.

Interfaces scellées

Comme les classes scellées, les interfaces peuvent également être scellées. Une telle interface peut permettre la sélection de ses interfaces ou classes enfants, qui peuvent l'étendre à l'aide de permits . Voici un bon exemple :
public sealed interface Device permits Electronic, Physical,
DeviceImpl {
}
Ici, l' interface Device permet aux interfaces électroniques et physiques de l'étendre et à la classe DeviceImpl pour une implémentation ultérieure.

Dossiers scellés

Les classes scellées peuvent être utilisées avec les entrées introduites dans Java 16. Une entrée ne peut pas étendre une classe normale, elle ne peut donc implémenter qu'une interface privée. De plus, la notation implique final . Par conséquent, une entrée ne peut pas utiliser le mot-clé permits car elle ne peut pas être sous-classée. Autrement dit, il n’existe qu’une hiérarchie à un seul niveau avec des enregistrements. Voici un exemple :
public sealed interface Device permits Laptop {
}
public record Laptop(String brand) implement Device {
}

Aide à la réflexion

Java Reflection prend en charge les classes scellées. Les deux méthodes suivantes ont été ajoutées à java.lang.Class :

1. getPermisSubclasses()

Cela renvoie un tableau java.lang.Class contenant toutes les classes autorisées par cet objet de classe. Exemple:
Device c = new Device();
Class<? extends Device> cz = c.getClass();
Class<?>[] permittedSubclasses = cz.getPermittedSubclasses();
for (Class<?> sc : permittedSubclasses){
  System.out.println(sc.getName());
}
Conclusion:
Ordinateur portable

2.isSealed()

Cela renvoie vrai si la classe ou l'interface dans laquelle elle est appelée est scellée. C'est tout pour l'instant sur les classes scellées ajoutées dans Java 17. J'espère que cet article a été informatif.

4 façons de mettre en œuvre Singleton

Source : Medium Aujourd'hui, vous apprendrez plusieurs façons d'implémenter le modèle de conception Singleton. Le modèle de conception Singleton est largement utilisé dans les projets Java. Il fournit un contrôle d'accès aux ressources, telles qu'une connexion socket ou base de données. On m'a déjà demandé d'implémenter un singleton lors d'un entretien pour un poste de développeur Web dans une grande entreprise de puces. C'était mon premier entretien pour un poste Web, et je n'ai pas fait beaucoup de préparation, j'ai donc choisi la solution la plus difficile : l'instanciation paresseuse. Mon code n'était correct qu'à 90% et pas assez efficace, j'ai fini par perdre au tour final... J'espère donc que mon article vous sera utile.

Instanciation précoce

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

    public static Singleton getInstance() {
        return instance;
    }
}
Étant donné que l'objet est déjà créé lors de l'initialisation, il n'y a pas de problème de sécurité des threads ici, mais il gaspille des ressources mémoire si personne ne l'utilise.

Implémentation paresseuse

class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
Lors de l'utilisation d'un modèle d'initialisation paresseuse, l'objet est créé à la demande. Cependant, cette méthode présente un problème de sécurité des threads : si deux threads sont démarrés sur la ligne 5 en même temps, ils créeront deux instances Singleton. Pour éviter cela, nous devons ajouter un verrou :
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;
    }
}
Verrouillage à double vérification (DCL) : Il n'y a pas de verrouillage sur la ligne 6, cette ligne fonctionnera donc très rapidement si l'objet a déjà été créé. Pourquoi devons-nous revérifier instance == null ? Parce qu'il y a peut-être deux threads introduits à la ligne 7 : le premier a initié l'objet, le second attend le verrou Singleton.class . S'il n'y a pas de vérification, le deuxième thread recréera à nouveau l'objet singleton. Cependant, cette méthode reste dangereuse pour les threads. La ligne 9 peut être divisée en trois lignes de byte code :
  1. Allouer de la mémoire.
  2. Objet d'initialisation.
  3. Attribuez un objet à la référence d'instance.
Étant donné que la JVM peut fonctionner dans le désordre, la machine virtuelle peut attribuer un objet à une référence d'instance avant l'initialisation. Un autre thread voit déjà l' instance != null , il commencera à l'utiliser et provoquera un problème. Nous devons donc ajouter volatile à l'instance, le code devient alors comme ceci :
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;
    }
}

Utiliser une classe interne statique

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 est une classe interne statique, elle n'est initialisée que lorsque la méthode getInstance est appelée . La classe init de la JVM exécutera <clinit> cmd , puis la JVM elle-même s'assurera qu'un seul thread peut appeler <clinit> sur la classe cible, les autres threads attendront.

Enum en tant que singleton

public enum EnumSingleton {
    INSTANCE;
    int value;
    public int getValue() {
        return value;
    }
    public int setValue(int v) {
        this.value = v;
    }
}
Par défaut, une instance d'énumération est thread-safe, vous n'avez donc pas à vous soucier d'une double vérification du verrouillage, et elle est assez facile à écrire.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION