Menu
CoddyTech

Parâmetros de Tipos Delimitados

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy. Lição 56 de 87.

Até agora, nossos parâmetros de tipo genérico podem aceitar qualquer tipo. Mas e se você precisar restringi-los?

Por exemplo, um método que calcula a soma de números não deve aceitar strings. Parâmetros de tipo limitados permitem limitar quais tipos podem ser usados com seus genéricos.

Use a palavra-chave extends para definir um limite superior em um parâmetro de tipo:

class NumberBox<T extends Number> {
    private T value;
    
    public NumberBox(T value) {
        this.value = value;
    }
    
    public double getDoubleValue() {
        return value.doubleValue();  // Pode chamar métodos de Number!
    }
}

NumberBox<Integer> intBox = new NumberBox<>(42);
NumberBox<Double> doubleBox = new NumberBox<>(3.14);
// NumberBox<String> strBox = new NumberBox<>("Hi");  // Erro de compilação!

O limite T extends Number significa que T deve ser Number ou qualquer uma de suas subclasses (Integer, Double, etc.). Isso também permite chamar methods definidos em Number no parâmetro de tipo.

Você pode especificar múltiplos limites usando &. Se um limite for uma classe, ele deverá vir primeiro:

class DataProcessor<T extends Number & Comparable<T>> {
    public boolean isGreater(T a, T b) {
        return a.compareTo(b) > 0;
    }
}

Aqui, T deve estender Number E implementar Comparable. Parâmetros de tipo limitados também funcionam com métodos genéricos:

public static <T extends Comparable<T>> T findMax(T a, T b) {
    return a.compareTo(b) > 0 ? a : b;
}

String result = findMax("apple", "banana");  // Retorna "banana"

Parâmetros de tipo limitados tornam seus genéricos mais poderosos, garantindo a segurança de tipos e permitindo o acesso a métodos específicos do tipo limitado.

challenge icon

Desafio

Fácil

Vamos criar uma calculadora de estatísticas que funcione apenas com tipos numéricos! Você usará parâmetros de tipo delimitados para garantir que sua calculadora processe apenas números, além de ter acesso a métodos úteis da classe Number.

Você organizará seu código em três arquivos:

  • NumberStats.java: crie uma classe genérica que calcule estatísticas para valores numéricos. Sua classe NumberStats<T extends Number> deve armazenar dois campos privados do tipo T: value1 e value2. Inclua um construtor que aceite ambos os valores. Adicione um método getSum() que retorne a soma dos dois valores como um double (use o método doubleValue() herdado de Number). Adicione também um método getAverage() que retorne a média dos dois valores como um double.
  • ComparableBox.java: crie uma classe genérica com múltiplos limites que possa encontrar o maior entre dois valores. Sua classe ComparableBox<T extends Number & Comparable<T>> deve armazenar dois campos privados do tipo T: first e second. Inclua um construtor que aceite ambos os valores. Adicione um método getMax() que retorne o maior valor usando compareTo(). Adicione também um método getMaxAsDouble() que retorne o maior valor convertido para um double.
  • Main.java: coloque seus genéricos delimitados em ação! Você receberá quatro entradas: dois inteiros e dois valores de ponto flutuante.

    Primeiro, crie um NumberStats<Integer> com os dois valores inteiros. Imprima a soma e a média:

    Integer sum: [sum]
    Integer average: [average]

    Em seguida, crie um NumberStats<Double> com os dois valores de ponto flutuante. Imprima a soma e a média:

    Double sum: [sum]
    Double average: [average]

    Por fim, crie um ComparableBox<Integer> com os dois valores inteiros e imprima:

    Max integer: [max]
    Max as double: [maxAsDouble]

Você receberá quatro entradas nesta ordem: primeiro inteiro, segundo inteiro, primeiro valor de ponto flutuante, segundo valor de ponto flutuante.

Observe como o limite T extends Number permite chamar doubleValue() em seu tipo genérico. Isso não seria possível com um parâmetro de tipo sem limite. E os múltiplos limites em ComparableBox garantem que você possa converter para double E comparar valores!

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Ler entradas
        int int1 = scanner.nextInt();
        int int2 = scanner.nextInt();
        double double1 = scanner.nextDouble();
        double double2 = scanner.nextDouble();
        
        // TODO: Crie um NumberStats<Integer> com os dois valores inteiros
        // Imprima a soma e a média no formato:
        // Integer sum: [sum]
        // Integer average: [average]
        
        // TODO: Crie um NumberStats<Double> com os dois valores double
        // Imprima a soma e a média no formato:
        // Double sum: [sum]
        // Double average: [average]
        
        // TODO: Crie um ComparableBox<Integer> com os dois valores inteiros
        // Imprima o máximo e o máximo como double no formato:
        // Max integer: [max]
        // Max as double: [maxAsDouble]
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Java online