Atualizado: 16/08/2025

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

Restrições de Generics em Java

Em Java, ao declarar um parâmetro de tipo em um recurso genérico, ele pode, por padrão, representar qualquer tipo. No entanto, há situações em que é necessário restringir esse parâmetro para que aceite apenas determinados tipos. Essas restrições permitem especificar uma classe base ou interface que o tipo genérico deve seguir.

Para criar uma restrição, adiciona-se a palavra extends após o nome do parâmetro de tipo, seguida da classe ou interface que definirá o limite. Por exemplo:

class Account { }
class Transaction<T extends Account> { }

Nesse caso, o parâmetro T de Transaction está restrito à classe Account. Isso significa que T pode ser Account ou qualquer classe que a estenda.


Exemplo com classe base

O código a seguir demonstra um cenário em que a classe Transaction representa a transferência de valores entre duas contas, sendo parametrizada com T restrito a Account. Assim, o compilador reconhece que os objetos de T têm os métodos definidos em Account.

public class Program {
    public static void main(String[] args) {
        Account acc1 = new Account("1876", 4500);
        Account acc2 = new Account("3476", 1500);

        Transaction<Account> tran1 = new Transaction<>(acc1, acc2, 4000);
        tran1.execute();
        tran1 = new Transaction<>(acc1, acc2, 4000);
        tran1.execute();
    }
}

class Transaction<T extends Account> {
    private T from;
    private T to;
    private int sum;

    Transaction(T from, T to, int sum) {
        this.from = from;
        this.to = to;
        this.sum = sum;
    }

    public void execute() {
        if (from.getSum() > sum) {
            from.setSum(from.getSum() - sum);
            to.setSum(to.getSum() + sum);
            System.out.printf("Account %s: %d \nAccount %s: %d \n",
                from.getId(), from.getSum(), to.getId(), to.getSum());
        } else {
            System.out.printf("Operation is invalid");
        }
    }
}

class Account {
    private String id;
    private int sum;

    Account(String id, int sum) {
        this.id = id;
        this.sum = sum;
    }

    public String getId() { return id; }
    public int getSum() { return sum; }
    public void setSum(int sum) { this.sum = sum; }
}

Se a restrição não fosse aplicada, o compilador não garantiria que T possui os métodos de Account, resultando em erro de compilação.


Restrições com tipos genéricos parametrizados

As restrições também podem envolver classes genéricas que possuem seus próprios parâmetros. No exemplo abaixo, Transaction é limitada a tipos Account<String>, garantindo que o identificador da conta seja do tipo String.

public class Program {
    public static void main(String[] args) {
        Account<String> acc1 = new Account<>("1876", 4500);
        Account<String> acc2 = new Account<>("3476", 1500);

        Transaction<Account<String>> tran1 = new Transaction<>(acc1, acc2, 4000);
        tran1.execute();
        tran1 = new Transaction<>(acc1, acc2, 4000);
        tran1.execute();
    }
}

class Transaction<T extends Account<String>> {
    private T from;
    private T to;
    private int sum;

    Transaction(T from, T to, int sum) {
        this.from = from;
        this.to = to;
        this.sum = sum;
    }

    public void execute() {
        if (from.getSum() > sum) {
            from.setSum(from.getSum() - sum);
            to.setSum(to.getSum() + sum);
            System.out.printf("Account %s: %d \nAccount %s: %d \n",
                from.getId(), from.getSum(), to.getId(), to.getSum());
        } else {
            System.out.printf("Operation is invalid");
        }
    }
}

class Account<T> {
    private T id;
    private int sum;

    Account(T id, int sum) {
        this.id = id;
        this.sum = sum;
    }

    public T getId() { return id; }
    public int getSum() { return sum; }
    public void setSum(int sum) { this.sum = sum; }
}

Restrições com interfaces

Além de classes, uma restrição também pode ser definida com interfaces. Nesse caso, o tipo passado para o parâmetro genérico precisa implementar a interface indicada, garantindo que possua seus métodos.

public class Program {
    public static void main(String[] args) {
        Account acc1 = new Account("1235rwr", 5000);
        Account acc2 = new Account("2373", 4300);
        Transaction<Account> tran1 = new Transaction<>(acc1, acc2, 1560);
        tran1.execute();
    }
}

interface Accountable {
    String getId();
    int getSum();
    void setSum(int sum);
}

class Account implements Accountable {
    private String id;
    private int sum;

    Account(String id, int sum) {
        this.id = id;
        this.sum = sum;
    }

    public String getId() { return id; }
    public int getSum() { return sum; }
    public void setSum(int sum) { this.sum = sum; }
}

class Transaction<T extends Accountable> {
    private T from;
    private T to;
    private int sum;

    Transaction(T from, T to, int sum) {
        this.from = from;
        this.to = to;
        this.sum = sum;
    }

    public void execute() {
        if (from.getSum() > sum) {
            from.setSum(from.getSum() - sum);
            to.setSum(to.getSum() + sum);
            System.out.printf("Account %s: %d \nAccount %s: %d \n",
                from.getId(), from.getSum(), to.getId(), to.getSum());
        } else {
            System.out.printf("Operation is invalid");
        }
    }
}

Restrições múltiplas

É possível aplicar mais de uma restrição ao mesmo parâmetro de tipo. O Java permite que o tipo genérico seja, ao mesmo tempo, subclasse de uma determinada classe e implemente uma ou mais interfaces. Por exemplo:

class Person { }
interface Accountable { }

class Transaction<T extends Person & Accountable> { }

Nesse cenário, o tipo T precisa herdar de Person e implementar Accountable simultaneamente.


Resumo

  • Limitam os tipos aceitos por um parâmetro genérico para garantir que possuam certos métodos ou características.
  • São definidas com extends, podendo indicar uma classe, interface ou ambas.
  • Permitem que o compilador reconheça e use métodos herdados pelo tipo genérico.
  • Podem ser aplicadas em classes, métodos ou parâmetros genéricos.
  • Suportam múltiplas restrições combinando classe base e 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