Estructuras de Datos
1. Generics
Generics o Programación Genérica
ArrayList<String> archivos = new ArrayList<String>();
Parámetro de tipo ó inferencia de Tipo
Reutilización de código ArrayList<File> archivos = new ArrayList<File>();
2
1. Generics
¿Se puede hacer lo mismo sin Programación
Genérica?
Object
Inconvenientes
1. Uso continuo del Casting
2. Complicación del código
3. No hay posibilidad de comprobación de errores
3
1. Generics
¿Por qué usar la programación genérica?
Mayor sencillez del código
Reutilización de código en
diferentes escenarios
Comprobación de errores en
tiempo de compilación
4
1. Generics
INTRODUCCIÓN
Java permite definir clases con variables o parámetros que representan tipos =>
Clases genéricas
Esto es posible, cuando el tipo de un dato no afecta al tratamiento que se le va a
dar a ese dato.
Los genéricos permiten que métodos y clases puedan operar con distintos tipos
de objetos proporcionando seguridad en tiempo de compilación.
Los tipos de datos genéricos asumen el tipo de dato que le pasemos a la clase
cuando la instanciamos.
5
1. Generics
CARACTERÍSTICAS
Los generics permiten usar tipos para parametrizar las clases, interfaces
y métodos al definirlas. Los beneficios son:
● Comprobación de tipos más fuerte en tiempo de compilación.
● Eliminación de casts aumentando la legibilidad del código.
● Posibilidad de implementar algoritmos genéricos, con tipado
seguro.
6
1. Generics
EJEMPLO
import [Link];
public class Ejemplo {
public static void main(String[] args) {
ArrayList lista = new ArrayList();
[Link]("Hola mundo");
[Link]("Estructuras de datos");
[Link]("Universidad del Quindío");
String cadena = (String) [Link](0);
[Link](cadena);
}
7
1. Generics
EJEMPLO
import [Link];
public class Ejemplo {
public static void main(String[] args) {
ArrayList lista = new ArrayList();
[Link](22);
[Link]("Hola mundo");
[Link](new Persona(12, "Pepito", "Perez"));
String cadena = (String) [Link](0);
[Link](cadena);
}
8
1. Generics
EJEMPLO
Exception in thread "main" [Link]:
[Link] cannot be cast to [Link]
at [Link]([Link])
9
1. Generics
Sobrecarga de métodos
Evitar el uso de sobrecarga de métodos en algunos casos
public class MetodosSobrecargados {
public void imprimirArreglo(Integer[] arregloEntrada){
for ( Integer elemento : arregloEntrada )
[Link]( elemento + " " );
}
public void imprimirArreglo(Double[] arregloEntrada ){
for ( Double elemento : arregloEntrada )
[Link]( elemento + " " );
}
…. String, etc…
10
1. Generics
Si reemplazáramos los tipos de los elementos en cada método con un nombre genérico
(por convención, se usa E para representar el tipo “elemento”), entonces los dos métodos
se pueden resumir en uno solo.
Sucede que, si podemos reemplazar el tipo de los elementos del arreglo en cada uno de
los dos métodos con un solo tipo genérico, entonces debemos poder declarar un método
imprimirArreglo que imprima el contenido del arreglo sin importar su tipo.
11
1. Generics
public void imprimirArreglo( E[] arregloEntrada ) {
for ( E elemento : arregloEntrada )
[Link]( elemento + " " );
}
12
1. Generics
En Java 5 se introdujeron los generics para dotar al lenguaje de una mejor
comprobación de tipos en tiempo de compilación y al mismo tiempo eliminar
los cast que hasta entonces eran necesarios al usar las colecciones. Dada la
lentitud de adopción que suele haber en la plataforma Java en los grandes
entornos empresariales puede que aún no los hayamos usado extensamente o
tengamos alguna duda en su uso.
Los generics son importantes ya que permiten al compilador informar de muchos errores de
compilación que hasta el momento solo se descubrirán en tiempo de ejecución, al mismo tiempo
permiten eliminar los cast, reduciendo la repetición y aumentando la legibilidad el código.
14
1. Generics
Por convención, los nombres de los parámetros de tipo se denominan letras mayúsculas simples para que un
parámetro de tipo se pueda distinguir fácilmente. A continuación se muestra la lista de nombres de parámetros
de tipo de uso común:
● E - Element, y es utilizado principalmente por el marco de Java Collections.
● K - Key, y se utiliza principalmente para representar el tipo de parámetro de clave de un mapa.
● V - Value, y se utiliza principalmente para representar el tipo de parámetro de valor de un mapa.
● N : número, y se utiliza principalmente para representar números.
● T - Type, y se utiliza principalmente para representar el primer parámetro de tipo genérico.
● S - Type, y se utiliza principalmente para representar el segundo parámetro de tipo genérico.
● U - Type, y se utiliza principalmente para representar el tercer parámetro de tipo genérico.
● V - Type, y se utiliza principalmente para representar el cuarto parámetro de tipo genérico.
● ?, Comodín (Cualquier tipo). Ejemplo: List <? extends Number>
15
1. Generics
Un tipo usando generics tiene el siguiente aspecto, por ejemplo usando una clase Box contenedor de una
referencia a un tipo no determinado en la definición de la clase pero que lo será en su uso. Una clase
genérica puede tener múltiples argumentos de tipos y los argumentos pueden ser a su vez tipos
genéricos. Después del nombre de la clase se puede indicar la lista de parámetros de tipos con el formato
\<T1, T2, T3, ...\>.
Box<Integer> integerBox1 = new Box<Integer>();
public class Box<T> { Box<Integer> integerBox2 = new Box<>();
private T t;
La inferencia de tipo representa la capacidad del compilador de Java para
observar la invocación de un método y su declaración correspondiente para
public T get() { return t; }
verificar y determinar los argumentos de tipo. El algoritmo de inferencia verifica
public void set(T t) { this.t = t; }
los tipos de argumentos y, si está disponible, se devuelve el tipo asignado. Los
} algoritmos de inferencia intentan encontrar un tipo específico que pueda
cumplir con todos los parámetros de tipo.
El compilador genera una advertencia de conversión no verificada en caso de
que no se utilice la inferencia de tipo.
● Box : Box es una clase genérica.
● <> : El operador de diamante denota inferencia de tipo.
Para mantener la compatibilidad con versiones anteriores a Java 5 los tipos
genéricos que al usarse no indican argumentos de tipo se denominan raw. El Box rawBox = new Box();
compilador indicará una advertencia como un uso potencialmente peligroso ya
que no podrá validar los tipos.
16
1. Generics
Motivación
• Supongamos que en un programa necesitamos una
clase ParEnteros:
public class ParEnteros {
private int a, b;
public ParEnteros(int a, int b){
this.a = a;
this.b = b;
}
public ParEnteros swap (){
return new ParEnteros(b, a);
}
}
17
1. Generics
Motivación
• Pero también necesitamos un clase ParCaracteres con
los mismos métodos que la anterior.
• La implementación de los métodos es la misma, porque
no depende del tipo del dato manipulado =>
abstraemos el tipo convirtiéndolo en un parámetro
genérico T.
18
1. Generics
Ejemplo clase genérica Par
public class Par<T> {
private T a, b;
public Par(T a, T b){
this.a = a;
this.b = b;
}
public Par<T> swap (){
return new Par<T>(b, a);
}
}
19
1. Generics
Ejemplo clase genérica Par
public class Prueba {
public static void main(String[] args) {
// Instanciación de la clase genérica para Integer
// No se puede usar int porque no es una clase
Par<Integer> p = new Par<Integer>(1,2);
// Instanciación de la clase genérica para Character
Par<Character> p1 = new Par<Character>('a','b');
p = [Link]();
p1 = [Link]();
}
}
20
1. Generics
Restringiendo el parámetro genérico
• Supongamos que deseamos añadir a la clase
Par un método max():
public T max(){
return ((a>b) ? a : b);
}
• Si añadimos este método sin más, obtendremos un
error de compilación, ya que a y b no tienen por qué
ser de un tipo comparable con >.
21
1. Generics
Restringiendo el parámetro genérico
• Debemos decirle al compilador que el tipo T sólo representará tipos
de valores comparables con el > o una función equivalente
(compareTo).
public class Par<T extends Comparable> {
private T a, b;
public Par(T a, T b){
this.a = a;
this.b = b;
}
public T max(){
return (([Link](b)>0) ? a : b);
}
..................
22
1. Generics
Restringiendo el parámetro genérico
class Stats< T extends Number > {
private T[] nums;
Stats(T[] o) {
nums = o;
}
double average() {
double sum = 0.0;
for(int i=0; i < [Link]; i++)
sum += nums[i].doubleValue();
return sum / [Link];
}
}
23
1. Generics
Clases genéricas como parámetros de funciones
boolean sameAvg(Stats<?> ob) {
if(average() == [Link]())
return true;
else
return false;
}
• Por medio del tipo Stats<?> indicamos que esta función puede
recibir un objeto de cualquier instancia de la clase genérica
Stats<T extends Number>
24
1. Generics
Clases genéricas como parámetros de funciones
Integer inums[] = { 1, 2, 3, 4, 5 };
Stats<Integer> iob = new Stats<Integer>(inums);
double v = [Link]();
[Link]("iob average is " + v);
Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Double> dob = new Stats<Double>(dnums);
double w = [Link]();
[Link]("dob average is " + w);
[Link]("Averages of iob and dob ");
if([Link](dob))
[Link]("are the same.");
else
[Link]("differ.");
25
1. Generics
En Java un tipo puede ser asignado a otro mientras el primero sea compatible con el segundo, es decir tengan
una «relación es un». Una referencia de Object puede referenciar una instancia de Integer (un Integer es
un Object).
Object object = new Object();
Integer integer = new Integer(10);
object = integer;
Sin embargo, en el caso de los generics, ¿una referencia de Box<Number> puede aceptar una instancia
Box<Integer> or Box<Double> aun siendo Integer y Double subtipos de Number?.
La respuesta es no, ya que Box<Integer> y Box<Double> en Java no son subtipos
de Box<Number>. La jerarquía de tipos es la siguiente:
26
1. Generics
Los tipos genéricos pueden extenderse o implementarse y mientras no se cambie el
tipo del argumento la «relación es un» se preserva. De modo que ArrayList<String> es
un subtipo de List<String> que a su vez es un subtipo de Collection<String>.
27
MiClaseGenerica<? extends Empleado> p //limite superior Persona
Empleado
Gerente Administrador
Cajero
MiClaseGenerica<? super Auxiliar> p //limite inferior
Auxiliar
1. Generics
En los generics un parámetro para un tipo ? se denomina wildcard siendo este un tipo desconocido. Son
usados para reducir las restricciones de un tipo de modo que un método pueda funcionar con una lista
de List<Integer>, List<Double> y List<Number>. El término List<Number> es más restrictivo que List<?
extends Number> porque el primero solo acepta una lista de Number y el segundo una lista de Number o
de sus subtipos. List<? extends Number> es un upper bounded wildcard (comodín delimitado superior).
Uno de las mayores confusiones al
usar generics es cuando usar
upper bounded wildcards (comodín
delimitado superior). o cuando
usar lower bounded wildcards
(comodín delimitado inferior)..
Se puede definir una lista de un tipo desconocido, List<?>, en casos en los que:
● La funcionalidad se puede implementar usando un tipo Object.
● Cuando el código usa métodos que no dependen del tipo de parámetro. Por ejemplo,
[Link] o [Link]. Unbounded Wildcard (comodín ilimitado)
[Link]
29
1. Generics
public class Operacion<T extends Number> {
public Number sumar(T a, T b){
return [Link]()+[Link]();
}
public double sumar(List<? extends Number> list){
double sum = 0;
for(Number n : list){
sum += [Link]();
}
return sum;
}
30
1. Generics - Retomando listas Enlazadas
Generics - Lista
Nuestra lista por ahora solo sirve para un tipo de dato: números enteros. Solo podemos
crear listas de números, pero qué pasa si yo quiero crear una lista de String o de
Personas, o de Colores.
Gracias a los generics podemos especificar el tipo de objeto que introduciremos en la
colección, de forma que el compilador conozca el tipo de objeto que vamos a utilizar,
evitándonos casting, instanceof, etc.
Para utilizar generics simplemente debemos agregar <T> después del nombre de la clase
en su declaración, luego reemplazar los tipos concretos T.
Nuestro código se vuelve más legible.
31
2. Iterable
Es una interface que está incluida en la api de Java.
Es una interface de uso habitual en las colecciones o estructuras de datos.
Implementar iterable obliga a sobreescribir un método que es iterator(). Este método
debe devolver un objeto de tipo Iterator.
32
2. Iterable
Indica que una clase se puede recorrer, para que esto se cumpla, dicha clase debe
representar una colección de elementos de cualquier tipo.
Ejemplo: Nuestra clase Lista.
Nodo 1 Nodo 2 Nodo 3
0 1 2
33
2. Iterable
public class Lista<T> implements Iterable<T> {
…
…
34
3. Iterator
La interfaz Iterator pertenece a Java Collections Framework.
Nos permite iterar sobre una colección de elementos.
Provee una interface uniforme para recorrer todas las colecciones.
Permite acceder a cada elemento de una colección sin necesidad de conocer la estructura
de la misma
3. Iterator
public class Lista<T> implements Iterable<T> {
…
…
public Iterator<T> iterator(){
return (debe retornar un objeto de tipo Iterator);
}
Iterable es una interface por lo tanto
debemos implementar sus métodos, en
este caso su único método es iterator()
36
3. Iterator
Para poder devolver un objeto de tipo Iterator (que es algo a lo que al fin y al cabo nos
obliga la interface iterable) necesitamos instanciar un objeto Iterator.
Para esto, definimos una clase interna dentro de la clase Lista denominada
IteratorListaSimple, que implementará la interface Iterator, y que nos permitirá
devolver una instancia de Iterator para nuestra clase Lista.
3. Iterator
Creamos nuestro iterator
protected class IteradorListaSimple implements Iterator<T>{
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
}
@Override
public T next() {
// TODO Auto-generated method stub
return null;
}
@Override
public void remove() {
// TODO Auto-generated method stub
}
}
38
3. Iterator
Para usarla debemos implementar sus métodos, que son:
boolean hasNext();
E next();
void remove();
39