JavaRush /Blogue Java /Random-PT /Pausa para café #143. Classes seladas em Java 17. 4 manei...

Pausa para café #143. Classes seladas em Java 17. 4 maneiras de implementar Singleton

Publicado no grupo Random-PT

Classes seladas em Java 17

Fonte: Codippa Neste post veremos classes seladas, um novo recurso introduzido no Java 17, e como declará-las e usá-las com exemplos. Pausa para café #143.  Classes seladas em Java 17. 4 maneiras de implementar Singleton - 1As classes seladas apareceram pela primeira vez no Java 15 como um recurso de visualização e, mais tarde, no Java 16 com o mesmo status. Este recurso tornou-se totalmente funcional com o lançamento do Java 17 ( JEP 409 ).

O que são aulas seladas?

Uma classe selada permite restringir ou selecionar subclasses. Uma classe não pode estender uma classe privada, a menos que esteja na lista de classes filhas permitidas da classe pai. A classe é selada usando a palavra-chave selada . A classe selada deve ser seguida pela palavra-chave permits , juntamente com uma lista de classes que podem estendê-la. Aqui está um exemplo:
public sealed class Device permits Computer, Mobile {
}
Esta declaração significa que Device só pode ser estendido pelas classes Computer e Mobile . Se qualquer outra classe tentar estendê-la, um erro do compilador será gerado. Uma classe que estende uma classe selada deve ter a palavra-chave final , selada ou não selada em sua declaração . Portanto, temos uma hierarquia de classes fixa. Como isso se relaciona com a criação de uma classe filha?
  1. final significa que não pode ser subclassificado posteriormente.

  2. selado significa que precisamos declarar classes filhas com permissões .

  3. não selado significa que aqui encerramos a hierarquia pai-filho .

Por exemplo, Computador permite as classes Laptop e Desktop , desde que o próprio Laptop permaneça não lacrado . Isso significa que o Laptop pode ser estendido por classes como Apple , Dell , HP e assim por diante.

Os principais objetivos da introdução de aulas seladas são:

  1. Até agora, você só podia limitar a extensão de uma classe usando a palavra-chave final . Uma classe selada controla quais classes podem estendê-la, incluindo-as na lista de permissões.

  2. Também permite que a classe controle quais delas serão suas classes filhas.

Regras

Algumas regras a serem lembradas ao usar classes seladas:
  1. Uma classe selada deve definir classes que possam estendê-la usando permissões . Isso não é necessário se as classes filhas forem definidas na classe pai como uma classe interna.

  2. A classe filha deve ser final , sealed ou non-sealed .

  3. Uma classe filha permitida deve estender sua classe pai selada.

    Ou seja, se a classe selada A permite a classe B, então B deve estender A.

  4. Se a classe lacrada estiver em um módulo, então as classes filhas também deverão estar no mesmo módulo, ou no mesmo pacote se a classe lacrada pai estiver em um módulo sem nome.

  5. Somente classes diretamente permitidas podem estender uma classe selada. Ou seja, se A é uma classe selada que permite que B a estenda, então B também é uma classe selada que permite C.

    Então C só pode estender B, mas não pode estender A diretamente.

Interfaces seladas

Assim como as classes seladas, as interfaces também podem ser seladas. Tal interface pode permitir a seleção de suas interfaces ou classes filhas, que podem estendê-la usando permits . Aqui está um bom exemplo:
public sealed interface Device permits Electronic, Physical,
DeviceImpl {
}
Aqui, a interface Device permite que as interfaces Eletrônica e Física a estendam e a classe DeviceImpl para implementação subsequente.

Registros Selados

Classes seladas podem ser usadas com entradas introduzidas em Java 16. Uma entrada não pode estender uma classe regular, portanto, só pode implementar uma interface privada. Além disso, a notação implica final . Portanto, uma entrada não pode usar a palavra-chave permits porque não pode ser subclassificada. Ou seja, existe apenas uma hierarquia de nível único com registros. Aqui está um exemplo:
public sealed interface Device permits Laptop {
}
public record Laptop(String brand) implement Device {
}

Suporte de reflexão

Java Reflection fornece suporte para classes seladas. Os dois métodos a seguir foram adicionados a java.lang.Class :

1. getPermitSubclasses()

Isso retorna um array java.lang.Class contendo todas as classes permitidas por este objeto de classe. Exemplo:
Device c = new Device();
Class<? extends Device> cz = c.getClass();
Class<?>[] permittedSubclasses = cz.getPermittedSubclasses();
for (Class<?> sc : permittedSubclasses){
  System.out.println(sc.getName());
}
Conclusão:
Computador Móvel

2.isSealed()

Isso retorna verdadeiro se a classe ou interface na qual é chamada estiver selada. Por enquanto, isso é tudo sobre as classes seladas adicionadas no Java 17. Espero que este artigo tenha sido informativo.

4 maneiras de implementar Singleton

Fonte: Medium Hoje você aprenderá diversas maneiras de implementar o padrão de design Singleton. O padrão de design Singleton é amplamente utilizado em projetos Java. Ele fornece controle de acesso a recursos, como um soquete ou conexão de banco de dados. Certa vez, fui solicitado a implementar um singleton durante uma entrevista para um cargo de desenvolvedor web em uma grande empresa de chips. Esta foi minha primeira entrevista para um cargo na web e não fiz muita preparação, então escolhi a solução mais difícil: instanciação preguiçosa. Meu código estava apenas 90% correto e não foi eficiente o suficiente, acabei perdendo na rodada final... Então espero que meu artigo seja útil para você.

Instanciação antecipada

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

    public static Singleton getInstance() {
        return instance;
    }
}
Como o objeto já foi criado na inicialização, não há problema de segurança de thread aqui, mas ele desperdiça recursos de memória se ninguém o estiver usando.

Implementação preguiçosa

class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
Ao usar um padrão de inicialização lenta, o objeto é criado sob demanda. No entanto, este método tem um problema de segurança de thread: se dois threads forem iniciados na linha 5 ao mesmo tempo, eles criarão duas instâncias Singleton. Para evitar isso, precisamos adicionar um bloqueio:
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): Não há bloqueio na linha 6, portanto esta linha funcionará muito rapidamente se o objeto já tiver sido criado. Por que precisamos verificar novamente instance == null ? Porque talvez existam dois threads introduzidos na linha 7: o primeiro iniciou o objeto, o segundo está aguardando o bloqueio Singleton.class . Se não houver verificação, o segundo thread recriará novamente o objeto singleton. No entanto, esse método ainda é perigoso para threads. A linha 9 pode ser dividida em três linhas de código de bytes:
  1. Alocar memória.
  2. Objeto de inicialização.
  3. Atribuir objeto à referência de instância.
Como a JVM pode ficar fora de ordem, a máquina virtual pode atribuir um objeto a uma referência de instância antes da inicialização. Outro thread já vê a instância != null , começará a usá-la e causará um problema. Então precisamos adicionar volátil à instância, então o código fica assim:
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;
    }
}

Usando uma classe interna estática

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 é uma classe interna estática, só é inicializada quando o método getInstance é chamado . A classe init na JVM executará <clinit> cmd , então a própria JVM garantirá que apenas um thread possa chamar <clinit> na classe de destino, outros threads irão esperar.

Enum como um singleton

public enum EnumSingleton {
    INSTANCE;
    int value;
    public int getValue() {
        return value;
    }
    public int setValue(int v) {
        this.value = v;
    }
}
Por padrão, uma instância enum é thread-safe, então não há necessidade de se preocupar com o bloqueio verificado duas vezes e é bastante fácil de escrever.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION