01 ‐ Java Generics - Cyb3rh4ck/java-core-fundamentals GitHub Wiki
Claro, estaré encantado de explicarte los Java Generics.
Los generics en Java se introdujeron en JDK 5 para proporcionar una manera de definir clases, interfaces y métodos con parámetros de tipo. Esto permite que el código sea más flexible y reutilizable, al mismo tiempo que mejora la seguridad y la legibilidad del tipo. Con generics, puedes definir una clase o método que opere en tipos específicos sin tener que especificar los tipos exactos hasta que se use el código.
- Seguridad de Tipo: Los generics permiten que el compilador compruebe tipos en tiempo de compilación, reduciendo la posibilidad de errores de tipo en tiempo de ejecución.
- Reutilización de Código: Puedes escribir métodos y clases que operen con cualquier tipo de datos, aumentando la reutilización del código.
- Eliminación de Castings Explícitos: Los generics permiten que el código sea más legible y menos propenso a errores al eliminar la necesidad de castings explícitos.
Una clase genérica puede definirse utilizando un parámetro de tipo dentro de los ángulos < >
.
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
Aquí, T
es un parámetro de tipo que puede ser reemplazado por cualquier tipo concreto cuando se crea una instancia de Box
.
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello, Generics!");
Box<Integer> integerBox = new Box<>();
integerBox.setContent(123);
Los métodos genéricos pueden definirse con parámetros de tipo de la misma manera.
public class Util {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
Puedes llamar a este método con cualquier tipo de array.
String[] stringArray = {"One", "Two", "Three"};
Util.<String>printArray(stringArray);
Integer[] integerArray = {1, 2, 3};
Util.<Integer>printArray(integerArray);
A veces, necesitas restringir los tipos que se pueden pasar a un parámetro de tipo. Esto se puede hacer utilizando bounded type parameters.
public class Util {
public static <T extends Number> int compare(T a, T b) {
return Double.compare(a.doubleValue(), b.doubleValue());
}
}
Aquí, T
debe ser una subclase de Number
.
Los wildcards (?
) son útiles cuando quieres trabajar con tipos genéricos pero no necesitas conocer el tipo exacto.
public void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
public void printUpperBoundedList(List<? extends Number> list) {
for (Number elem : list) {
System.out.println(elem);
}
}
public void printLowerBoundedList(List<? super Integer> list) {
list.add(1); // Solo se pueden agregar elementos Integer o sus subclases
}
Desde JDK 17, no ha habido cambios significativos en la forma en que funcionan los generics en comparación con las versiones anteriores. Sin embargo, la evolución general de Java ha llevado a mejoras en otros aspectos del lenguaje que pueden interactuar con los generics, como las mejoras en las interfaces funcionales y las clases record.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello, Generics!");
System.out.println(stringBox.getContent());
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
printList(integerList);
printUpperBoundedList(integerList);
}
public static void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
public static void printUpperBoundedList(List<? extends Number> list) {
for (Number elem : list) {
System.out.println(elem);
}
}
}
class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
En resumen, los generics en Java son una poderosa característica que mejora la seguridad de tipos y la reutilización del código. Aunque no ha habido cambios drásticos en los generics en las versiones recientes de JDK, continúan siendo una parte fundamental del lenguaje Java.