Menu
Coddy logo textTech

Parámetros de tipo delimitados

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 56 de 87.

Hasta ahora, nuestros parámetros de tipo genérico pueden aceptar cualquier tipo. ¿Pero qué pasa si necesitas restringirlos?

Por ejemplo, un método que calcula la suma de números no debería aceptar cadenas. Los parámetros de tipo acotados te permiten limitar qué tipos se pueden usar con tus genéricos.

Utiliza la palabra clave extends para establecer un límite superior en un 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();  // ¡Puede llamar a métodos de Number!
    }
}

NumberBox<Integer> intBox = new NumberBox<>(42);
NumberBox<Double> doubleBox = new NumberBox<>(3.14);
// NumberBox<String> strBox = new NumberBox<>("Hi");  // ¡Error de compilación!

El límite T extends Number significa que T debe ser Number o cualquiera de sus subclases (Integer, Double, etc.). Esto también te permite llamar a métodos definidos en Number en el parámetro de tipo.

Puedes especificar múltiples límites usando &. Si uno de los límites es una clase, debe ir primero:

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

Aquí, T debe extender Number E implementar Comparable. Los parámetros de tipo acotados también funcionan con 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");  // Devuelve "banana"

Los parámetros de tipo acotados hacen que tus genéricos sean más potentes al garantizar la seguridad de tipos, al tiempo que permiten el acceso a métodos específicos del tipo acotado.

challenge icon

Desafío

Fácil

¡Vamos a construir una calculadora de estadísticas que solo funcione con tipos numéricos! Utilizarás parámetros de tipo acotados (bounded type parameters) para asegurar que tu calculadora solo pueda procesar números, obteniendo al mismo tiempo acceso a métodos útiles de la clase Number.

Organizarás tu código en tres archivos:

  • NumberStats.java: Crea una clase genérica que calcule estadísticas para valores numéricos. Tu clase NumberStats<T extends Number> debe almacenar dos campos privados de tipo T: value1 y value2. Incluye un constructor que acepte ambos valores. Añade un método getSum() que devuelva la suma de ambos valores como un double (utiliza el método doubleValue() heredado de Number). También añade un método getAverage() que devuelva el promedio de los dos valores como un double.
  • ComparableBox.java: Crea una clase genérica con múltiples límites que pueda encontrar el mayor de dos valores. Tu clase ComparableBox<T extends Number & Comparable<T>> debe almacenar dos campos privados de tipo T: first y second. Incluye un constructor que acepte ambos valores. Añade un método getMax() que devuelva el valor más grande utilizando compareTo(). También añade un método getMaxAsDouble() que devuelva el valor más grande convertido a un double.
  • Main.java: ¡Da vida a tus genéricos acotados! Recibirás cuatro entradas: dos enteros y dos dobles.

    Primero, crea un NumberStats<Integer> con los dos valores enteros. Imprime la suma y el promedio:

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

    A continuación, crea un NumberStats<Double> con los dos valores dobles. Imprime la suma y el promedio:

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

    Finalmente, crea un ComparableBox<Integer> con los dos valores enteros e imprime:

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

Recibirás cuatro entradas en orden: primer entero, segundo entero, primer doble, segundo doble.

Observa cómo el límite T extends Number te permite llamar a doubleValue() en tu tipo genérico, algo que no podrías hacer con un parámetro de tipo no acotado. ¡Y los límites múltiples en ComparableBox aseguran que puedas tanto convertir a double COMO comparar valores!

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Lee las entradas
        int int1 = scanner.nextInt();
        int int2 = scanner.nextInt();
        double double1 = scanner.nextDouble();
        double double2 = scanner.nextDouble();
        
        // TODO: Crea un NumberStats<Integer> con los dos valores enteros
        // Imprime la suma y el promedio en el formato:
        // Integer sum: [sum]
        // Integer average: [average]
        
        // TODO: Crea un NumberStats<Double> con los dos valores double
        // Imprime la suma y el promedio en el formato:
        // Double sum: [sum]
        // Double average: [average]
        
        // TODO: Crea un ComparableBox<Integer> con los dos valores enteros
        // Imprime el máximo y el máximo como double en el formato:
        // Max integer: [max]
        // Max as double: [maxAsDouble]
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Java online