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.
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 claseNumberStats<T extends Number>debe almacenar dos campos privados de tipoT:value1yvalue2. Incluye un constructor que acepte ambos valores. Añade un métodogetSum()que devuelva la suma de ambos valores como undouble(utiliza el métododoubleValue()heredado de Number). También añade un métodogetAverage()que devuelva el promedio de los dos valores como undouble.ComparableBox.java: Crea una clase genérica con múltiples límites que pueda encontrar el mayor de dos valores. Tu claseComparableBox<T extends Number & Comparable<T>>debe almacenar dos campos privados de tipoT:firstysecond. Incluye un constructor que acepte ambos valores. Añade un métodogetMax()que devuelva el valor más grande utilizandocompareTo(). También añade un métodogetMaxAsDouble()que devuelva el valor más grande convertido a undouble.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]
}
}
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
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón IteratorPractica por tu cuenta: Compilador de Java online