Atualizado: 28/09/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Controle de Hierarquias com Classes e Interfaces sealed em Java

Classes e interfaces sealed (seladas) em Java são um mecanismo para controlar quais outras classes ou interfaces podem estendê-las ou implementá-las. Este recurso introduz um nível de controle e previsibilidade nas hierarquias de herança que antes só era possível por meio de mecanismos menos flexíveis, como o modificador final ou restrições de acesso.

Antes da introdução das classes sealed, uma hierarquia de classes em Java poderia ser totalmente aberta para extensão (qualquer classe poderia herdar dela) ou completamente fechada com o uso do final. As classes sealed oferecem um meio termo ideal: elas permitem declarar explicitamente quais classes podem ser subclasses diretas, prevenindo heranças inesperadas. O principal benefício dessa abordagem é a capacidade de modelar domínios com um conjunto fixo e conhecido de variações, o que permite ao compilador, por exemplo, garantir que uma expressão switch com Pattern Matching cubra todos os subtipos possíveis.

Para declarar uma classe ou interface como sealed, são utilizadas duas palavras chave: sealed e permits.

sealed class NomeDaClasse permits Subclasse1, Subclasse2, SubclasseN {
    // Conteúdo da classe
}

A palavra chave sealed é aplicada à superclasse para declará-la como selada. Em seguida, a cláusula permits especifica a lista exaustiva das únicas classes que têm permissão para serem suas herdeiras diretas.

sealed class Operation
    permits Sum, Subtract, Multiply {

}

Neste caso, apenas as classes Sum, Subtract e Multiply podem herdar de Operation. Qualquer outra tentativa de herança resultará em um erro de compilação.

// Erro de compilação: a classe Divide não tem permissão para herdar de Operation
class Divide extends Operation {

}

Regras para as Subclasses Permitidas

As classes listadas na cláusula permits devem seguir regras específicas:

  1. Localização: Devem estar no mesmo pacote que a classe sealed. Se o projeto utilizar módulos Java, devem pertencer ao mesmo módulo. (Caso a cláusula permits seja omitida, todas as subclasses diretas devem ser declaradas no mesmo arquivo fonte da superclasse sealed).
  2. Continuidade da Hierarquia: Cada subclasse permitida deve declarar explicitamente como a hierarquia de herança continua (ou termina) a partir dela, usando um dos três seguintes modificadores:

    • final: Encerra a herança. Impede qualquer extensão futura a partir desta subclasse, finalizando este ramo da hierarquia.
    • sealed: Continua a herança de forma restrita. A subclasse também deve ser sealed e especificar suas próprias subclasses permitidas com uma cláusula permits.
    • non-sealed: Abre a herança. Remove as restrições, permitindo que a subclasse seja estendida por qualquer outra classe, como em uma hierarquia de classes tradicional.

Exemplo de Classes sealed

Vamos analisar um exemplo simples.

class Program {
    public static void main(String[] args) {
        Operation add = new Sum(5, 4);
        Operation sub = new Subtract(5, 4);

        System.out.println(add.execute());      // 9
        System.out.println(sub.execute());      // 1
    }
}

sealed abstract class Operation
    permits Sum, Subtract {

    int op1;
    int op2;

    Operation(int op1, int op2) {
        this.op1 = op1;
        this.op2 = op2;
    }

    abstract int execute();
}

final class Sum extends Operation {
    Sum(int op1, int op2) {
        super(op1, op2);
    }

    @Override
    int execute() {
        return op1 + op2;
    }
}

final class Subtract extends Operation {
    Subtract(int op1, int op2) {
        super(op1, op2);
    }

    @Override
    int execute() {
        return op1 - op2;
    }
}

Aqui, a classe abstrata Operation é sealed e só pode ser herdada por Sum e Subtract. Ambas as subclasses são final, garantindo que a hierarquia de Operation é finita e completamente conhecida pelo compilador.

Exemplo Avançado

O exemplo a seguir demonstra uma hierarquia mais complexa.

class Program {
    public static void main(String[] args) {
        Operation add = new Sum(5, 4);
        Operation sub = new Subtract(5, 4);
        Operation neg = new Negation(5);
        Operation if1 = new IfOperation(true, 3, 7);

        System.out.println(add.execute());      // 9
        System.out.println(sub.execute());      // 1
        System.out.println(neg.execute());      // -5
        System.out.println(if1.execute());      // 3
    }
}

sealed abstract class Operation permits BinaryOperation, IfOperation {
    abstract int execute();
}

final class IfOperation extends Operation {
    // ... implementação
}

sealed abstract class BinaryOperation extends Operation
    permits Sum, Subtract {
    // ... implementação
}

final class Sum extends BinaryOperation {
    // ... implementação
}

non-sealed class Subtract extends BinaryOperation {
    // ... implementação
}

class Negation extends Subtract {
    Negation(int op) {
        super(0, op); // Equivalente a 0 - op
    }
}

Neste caso, a hierarquia de Operation se ramifica: IfOperation é final, encerrando seu ramo; BinaryOperation é sealed e continua a restrição para Sum e Subtract; por fim, Subtract é non-sealed, quebrando a restrição e permitindo que classes arbitrárias, como Negation, possam herdá-la.

Interfaces sealed

O conceito de tipos sealed também se aplica a interfaces. Uma interface sealed só pode ser implementada por classes ou estendida por outras interfaces que estejam listadas em sua cláusula permits. As mesmas regras de final, sealed e non-sealed se aplicam às classes e interfaces herdeiras.

public sealed interface Shape permits Rectangle, Circle {
    double area();
}

final class Rectangle implements Shape {
    // ... implementação
}

final class Circle implements Shape {
    // ... implementação
}

Resumo

  • Hierarquias Previsíveis: Classes e interfaces sealed criam hierarquias de herança finitas e conhecidas, restringindo quais outras classes ou interfaces podem herdá-las.
  • Sinergia com switch: O principal benefício é permitir que o compilador verifique a exaustividade do Pattern Matching em expressões switch, garantindo que todos os subtipos permitidos sejam tratados.
  • Cláusula permits: Lista explicitamente todas as subclasses diretas permitidas.
  • Obrigação das Subclasses: Cada subclasse permitida deve ser declarada como final, sealed ou non-sealed para definir como a hierarquia continua.
  • Aplicação Ampla: O conceito se aplica tanto a classes (abstratas ou concretas) quanto a interfaces.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com