Está en la página 1de 35

Herencia y clases abstractas

• Herencia
• La palabra clave extends
• Sobrescritura
• La palabra clave super
• Upcasting-Downcasting
• La clase Object
• Los métodos equals(Object) y toString()
• Clases abstractas

Algoritmos y Estructuras de Datos 2021


Herencia
• La programación orientada a objetos (POO) permite a las clases expresar
similitudes entre objetos que tienen características y comportamiento
común. Estas similitudes pueden expresarse usando herencia.
• El término herencia se refiere al hecho de que una clase hereda los
atributos (variables) y el comportamiento (métodos) de otra clase.

A
(superclase)
• La clase que hereda se llama subclase o clase
derivada. La clase B es subclase de la clase A.
• La clase A es la superclase o clase base de la B
clase B. (subclase)

La herencia toma una clase existente y construye una versión


especializada => reusabilidad de código
Algoritmos y Estructuras de Datos 2021
Herencia
• Una subclase puede agregar atributos y comportamiento a su superclase.
• Una subclase puede reemplazar o modificar el comportamiento heredado. Esto es
sobrescritura.
Java permite múltiples niveles de
herencia, pero la herencia es simple

Variables y métodos
de instancia comunes superclase
a todos los vehículos

subclases

Variables y métodos de instancia ESPECÍFICOS de cada tipo de vehículo


Algoritmos y Estructuras de Datos 2021
Herencia
La palabra clave extends
public class Vehiculo {
private String marca;
private double precio;
public class Camioneta extends Vehiculos { . . .
private char cajaCambios;
private boolean tieneDobleCabina;
private boolean es4x4; public void setMarca(String marca) {
public void setTieneDobleCabina(boolean tieneDobleCabina) { this.marca = marca;
this.tieneDobleCabina = tieneDobleCabina; }
} public String getMarca() {
return marca;
public boolean isTieneDobleCabina() { }
return tieneDobleCabina; . . .
} }
. . . Automáticamente, la subclase
} obtiene las variables y métodos
de la superclase
public class Auto extends Vehiculo {
private String tipo; // sedan, familiar, etc.
. . . public class Camion extends Vehiculo {
} private boolean tieneDobleCaja;
private int cargaMaxima;
¿Qué modificación deberíamos hacer para guardar si la public void setCargaMaxima(int cargaMaxima){
this.cargaMaxima = cargaMaxima;
“caja de cambios” de las Camionetas, Autos y Camiones
}
es manual o automática?
public int getCargaMaxima() {
Alcanza con agregar una variable de instancia en return cargaMaxima;
Vehiculo, todas las clases subclases la heredarán } . . .
automáticamente. }
Algoritmos y Estructuras de Datos 2021
Herencia
Invocación de métodos heredados

Vehiculo miAuto = new Vehiculo();


¿Qué puedo hacer sobre el objeto miAuto?

double p= miAuto.getPrecio();
String c= miAuto.getTipoCombustible();
Un objeto Camion es
if (miAuto.esUsado()) {.. .} un Vehiculo

Camion miCamion = new Camion();


¿Qué puedo hacer sobre el objeto miCamion ?

double p= miCamion.getPrecio(); se pueden invocar todos los


métodos heredados de Vehiculo.

if (miCamion.isTieneDobleCaja()) {.. .} también se pueden invocar


todos los métodos de Camión

Algoritmos y Estructuras de Datos 2021


Herencia
Sobrescritura de métodos
Un método sobrescribe a otro método cuando se define en una subclase y coincide
el nombre, tipo de retorno y lista de argumentos con un método ya definido en una
superclase.

La clase Camion hereda


todos los atributos de
Vehículo y especifica dos
adicionales, cargaMaxima y
tieneDobleCaja y
sobrescribe el método
detalles()

Es posible crear una clase nueva


basada en una existente, agregándole
características adicionales y
modificándole el comportamiento a la
superclase.

Algoritmos y Estructuras de Datos 2021


Herencia
Sobrescritura de métodos
public class Vehiculo { El método detalles(), definido en la clase Vehiculo, se
private String marca; reemplazó o sobrescribió en la subclase Camion.
private double precio;
. . . public class Test {
public static void main(String args[]){
public String detalles() { Vehiculo v = new Vehiculo();
return “Vehiculo marca: "+ getMarca()+ v.setMarca("Ford");
"\n”+ "Precio: "+ this.getPrecio(); v.setPrecio(12000.4);
} System.out.println( v.detalles());

// getters y setters: getMarca(), getPrecio() Camion c = new Camion(); Se ejecutan


} c.setMarca(“Scania"); métodos
c.setPrecio(35120.4); diferentes !!
c.setCargaMaxima(3000);
public class Camion extends Vehiculo { System.out.println (c.detalles());
private boolean tieneDobleCaja; }
private int cargaMaxima; }
public String detalles() {
return "Vehiculo marca: "+getMarca()+
"\n"+"Precio: "+getPrecio() +"\n" SALIDA
+"carga máxima:"+getCargaMaxima();
}

// getter y setter
}
Algoritmos y Estructuras de Datos 2021
Herencia
Sobrescritura de métodos – La palabra clave super
public class Vehiculo {
private String marca;
private double precio; ¿Es posible invocar al método
. . . detalles() de la clase Vehiculo desde
un método de la clase Camion?
public String detalles() {
return “Vehiculo marca: "+ getMarca()+
"\n” + "Precio: "+ getPrecio(); SI!!!!!
}

. . .
}
¿Cómo?
public class Camion extends Vehiculo { Usando la palabra clave super
private boolean tieneDobleCaja;
private int cargaMaxima;

public String detalles() {


return
return"Vehiculo marca: "+getMarca()+
super.detalles()+ “\n”
"\n"+"Precio: "+getPrecio() +"\n"
+ “carga máxima:” + getCargaMaxima();
+"carga máxima:"+getcargaMaxima();
}
.
}
Algoritmos y Estructuras de Datos 2021
Herencia
Upcasting - Downcasting
Tratar a una referencia de la clase derivada como una referencia de la clase base, se
denomina upcasting. Con el upcasting, la conversión es hacia arriba en la jerarquía de
herencia y se pierde el tipo específico del objeto. Para recuperar el tipo del objeto, se debe
mover hacia abajo en la jerarquía y a esto se lo llama downcasting.

downcasting
upcasting

El upcasting es seguro, la clase base tiene una interface que es igual o es un subconjunto de
la clase derivada. Pero, en el downcasting no ocurre lo mismo.
Algoritmos y Estructuras de Datos 2021
Herencia
Sobrescritura de métodos
upcasting

Vehiculo vc = new Camion();


vc.detalles();

¿Qué método se ejecuta?


El asociado con el objeto al que hace referencia la variable en
ejecución, es decir, Camion. Esta característica se llama binding
dinámico y es propio de los lenguajes OO

¿Qué imprime?
Vehiculo vc = new Camion();
vc.setMarca("Mercedes Benz");
vc.setPrecio(35120.4);
vc.setCargaMaxima(3000); No está visible para Vehiculo
System.out.println(vc.detalles());

NO Compila

Algoritmos y Estructuras de Datos 2021


Herencia
La clase Object
• La clase Object es la raíz de todas las clases JAVA y está ubicada en el
paquete java.lang
• Cuando se declara una clase sin usar la palabra clave extends el
compilador JAVA implícitamente agrega el código extends Object a la
declaración de la clase. Es equivalente a:
public class Vehiculo { public class Vehiculo extends Object{
private String marca; private String marca;
private double precio; private double precio;
. . . . . .

public String detalles() { public String detalles() {


return “Vehiculo marca: "+getMarca() return “Vehiculo marca: "+getMarca()
+ "\n”+"Precio: "+ getPrecio(); + "\n”+"Precio: "+ getPrecio();
} }
. . . . . .
} }

De esta manera, estamos habilitados para sobrescribir


los métodos heredados de Object.
Algoritmos y Estructuras de Datos 2021
Herencia
La clase Object – Los métodos equals(Object o) y toString()

• El método public boolean equals(Object obj){}, compara la igualdad de 2


objetos. La versión original del método equals(), devuelve true si las dos
referencias son iguales, es decir si apuntan al mismo objeto en memoria. Es
equivalente a usar el operador ==.
• El método public String toString(){}, retorna la dirección del objeto como
un String.
La clase Fecha definida debajo hereda los métodos equals(Object o) y toString()
de Object:
public class Fecha { Fecha f1 = new Fecha();
private int dia= 1; Fecha f2 = new Fecha(); f1 0x09a456
private int mes= 1; f1.equals(f2) false f2
private int año=2007; f1==f2 false 0x99f311
// métodos de instancia
f1.toString() Fecha@360be0
}

La intención del método equals(Object o) es comparar el contenido de dos


objetos y la del toString() es producir una representación textual, concisa,
legible y expresiva del contenido del objeto.
Algoritmos y Estructuras de Datos 2021
Herencia
La clase Object – Los métodos equals(Object o) y toString()
Sobrescribimos en la clase Fecha, los
public class Fecha {
private int dia = 1; Es un operador que permite métodos equals(Object o) y toString()
determinar la clase real del
private int mes = 1; objeto
heredados de Object:
private int año = 2006;
public boolean equals(Object o){ Ahora en la clase Fecha:
boolean result=false; • El método equals(Object o)
if ((o!=null) && (o instanceof Fecha)){
Fecha f=(Fecha)o; cumple su objetivo: comparar el
if ((f.getDia() ==this.getDia()) contenido de dos objetos de tipo
&&(f.getMes() ==this.getMes())&& Fecha. Es por esta razón que
(f.getAño() ==this.getAño()) ) result=true;
} frecuentemente se lo sobrescribe.
return result; } • El método toString() retorna un
public String toString(){ String con datos de objeto Fecha
return “Fecha :”+”getDia()+"-"+getMes()+"-"+getAño();
} en una representación legible.
. . .
public static void main(String args[]){
Fecha f1, f2;
f1 = new Fecha(); f1 0x09a456
f2 = new Fecha(); f2
System.out.println( f1==f2);
La salida es: 0x99f311
System.out.println( f1.equals(f2)); false
System.out.println( f1.toString()); true
}} 1-1-2006
Algoritmos y Estructuras de Datos 2021
Herencia y clases abstractas
En Programación Orientada a Objetos podríamos modelar un concepto abstracto
mediante una clase abstracta cuya finalidad NO es crear instancias como en las
clases que venimos definiendo hasta ahora.
Pensemos en una aplicación que dibuja figuras geométricas, podríamos dibujar por
ejemplo: círculos, rectángulos, triángulos, líneas rectas, etc. Todas las figuras
geométricas pueden cambiar de color, dibujarse en la pantalla, moverse, etc.,
pero cada una lo hace de una manera particular.

Por otro lado, una figura geométrica, es un


concepto abstracto, no es posible dibujarla o
redimensionarla, sólo sabemos que todas las
figuras geométricas concretas, como los círculos,
rectángulos, triángulos tienen esas capacidades.

Algoritmos y Estructuras de Datos 2019 Profesores : Laura Fava, Pablo Iuliano


Herencia y clases abstractas
Si tratamos de codificar esta clase, podríamos hacerlo así:
public class FiguraGeometrica {
private Color color;
private int x;
private int y;
public void mover(int x, int y){
this.x = x;
this.y = y;
}
public void setColor(Color nuevoColor) {
color = nuevoColor;
dibujar();
}
public void dibujar() { Esta clase genérica FiguraGeometrica NO
?? representa una figura real, y por lo tanto NO
} puede definir implementaciones para todos
public int area(){ sus métodos. ¿Qué hacemos?
?? La declaramos abstracta
}
}
Algoritmos y Estructuras de Datos 2019 Profesores : Laura Fava, Pablo Iuliano
Herencia y clases abstractas
El objetivo de definir una clase abstracta es lograr una interface de
comportamiento común para los objetos de las subclases (de la
clase abstracta) .
Se espera que una clase abstracta sea extendida por clases que
implementen todos sus métodos abstractos. En una clase abstracta
pueden existir métodos concretos y métodos abstractos.
¿Qué es un método abstracto? Es un método que NO tiene
implementación. Se define el nombre, el tipo de retorno, la lista de
argumentos, termina con “;” y se antepone la palabra clave
abstract. NO tiene código.
¿Para qué sirve un método sin código?
Para definir un comportamiento común para todos
los objetos de las subclases concretas
Algoritmos y Estructuras de Datos 2019 Profesores : Laura Fava, Pablo Iuliano
Herencia y clases abstractas
Para declarar una clase abstracta se antepone la palabra clave
abstract a la palabra clave class. Una clase abstracta es una clase que
solamente puede ser extendida, no puede ser instanciada.
public abstract class FiguraGeometrica {
// Color de la figura
private Color color; public class TestFiguras {
private int x; public static void main(String
private int y; args[]){
new FigurasGeometricas();
}
public void mover(int x, int y){
} Si se intenta crear objetos de una clase
this.x = x;
abstracta, fallará la compilación. El
this.y = y; compilador NO permite crear instancias de
} clases abstractas.
public void setColor(Color nuevoColor){
color = nuevoColor;
dibujar(); Una clase abstracta puede
} contener métodos abstractos y
public abstract void dibujar(); métodos concretos.
} Los métodos abstractos no tiene cuerpo, su
declaración termina con “;”
Algoritmos y Estructuras de Datos 2019 Profesores : Laura Fava, Pablo Iuliano
Herencia y clases abstractas

Las clases abstractas pueden declarar variables de clase


instancia
abstracta
métodos
abstractos Las clases abstractas pueden declarar métodos
concretos

clases
métodos
abstractos concretas

FiguraGeometrica es una clase abstracta y los métodos area() y dibujar() son abstractos.
Para que las subclases Rectangulo, Rombo y Circulo sean concretas, deben proveer una
implementación de cada uno de los método abstractos de la clase FiguraGeométrica.

Algoritmos y Estructuras de Datos 2019 Profesores : Laura Fava, Pablo Iuliano


Listas
Algunas operaciones
• Una Lista es una estructura de datos en donde los objetos están ubicados
en forma secuencial. A diferencia de la Pila y la Cola, en una Lista se
puede “agregar” y “eliminar” en cualquier posición.
• Puede estar implementada a través de:
• una estructura estática (arreglo)
• una estructura dinámica (usando nodos enlazados)
• Puede estar ordenada o no:
• Si está ordenada, los elementos se ubican siguiendo el orden de las claves
almacenadas en la lista.

• Si está desordenada, los elementos pueden aparecer en cualquier orden.

Algoritmos y Estructuras de Datos 2021


Listas
Algunas operaciones
Por simplicidad comenzaremos con elementos de tipo enteros.
elemento(int pos): retorna el elemento de la posición indicada
incluye(Integer elem): retorna true si elem está en la lista, false en caso contrario
agregarInicio(Integer elem): agrega al inicio de la lista
agregarFinal(Integer elem): agrega al final de la lista
agregarEn(Integer elem, int pos): agrega el elemento elem en la posición pos
eliminarEn(int pos): elimina el elemento de la posición pos
eliminar(Integer elem): elimina, si existe, el elemento elem
esVacia(): retorna true si la lista está vacía, false en caso contrario
tamanio(): retorna la cantidad de elementos de la lista
comenzar(): se prepara para iterar los elementos de la lista
proximo(): retorna el elemento y avanza al próximo elemento de la lista.
fin(): determina si llegó o no al final de la lista, retorna true si no hay mas elementos, false en
caso contrario
Algoritmos y Estructuras de Datos 2021
Listas sin Orden
Algunas operaciones: agregar

• elemento(int pos): retorna el elemento de la posición indicada por pos.

elemento(3)

resultado:

• incluye(Integer elem): retorna true si elem está contenido en la lista, false en caso
contrario

incluye(13)
resultado: true
incluye(7)
resultado: false

Algoritmos y Estructuras de Datos 2021


Listas sin Orden
Algunas operaciones: agregar

• agregarInicio(Integer elem): agrega el elemento elem al inicio de la lista

agregarInicio(3)

resultado:

• agregarFinal(Integer elem): agrega el elemento elem al final de la lista

agregarFinal(3)

resultado:

Algoritmos y Estructuras de Datos 2021


Listas sin Orden
Algunas operaciones: agregar

• agregarEn(Integer elem, int pos): agrega el elemento elem en la posición pos.

agregarEn(5,4)

resultado:

¿Cómo se comportan los métodos agregarInicio(Integer elem) y agregarFinal(Integer elem)


en términos de agregarEn(Integer elem, int pos) ?

agregarEn(elem,1) agregarEn(elem, tamanio()+1)

Algoritmos y Estructuras de Datos 2021


Listas sin Orden
Algunas operaciones: eliminar

• eliminarEn(int pos): elimina el elemento de la posición indicada

eliminarEn(3)

resultado:

• eliminar(Integer elem): elimina el elemento “elem” indicado

eliminar(13)

resultado:

Algoritmos y Estructuras de Datos 2021


Listas sin Orden
Implementaciones

Una lista puede estar implementada a través de:


•una estructura estática (arreglo)

•una estructura dinámica (nodos enlazados)

null

Algoritmos y Estructuras de Datos 2021


Listas sin Orden
Implementaciones
Independientemente de la estructura de datos usada para implementar la lista,
ambas responden al mismo conjunto de operaciones:
lista1.elemento(2): debe retornar 13, el valor del segundo nodo
lista2.elemento(2): debe retornar 13, el valor de la 2da componentes del arreglo (índice 1)
lista1.agregarInicio(12): debe agregar el 12 al inicio de la lista, actualizando referencias
lista2.agregarInicio(12): debe agregar el 12 al inicio de la lista, haciendo corrimiento a la derecha
lista1.agregarEn(8, 3): debe agregar un nuevo nodo entre los nodos con valor 13 y 14
lista2.agregarEn(8, 3): debe agregar el valor 8 donde está el valor 14 previo corrimiento a la derecha a
lista1.tamaño() 🡪 9 y lista2.tamaño() 🡪 9 partir de ese valor.

inicio final

lista1

null

lista2 el tamaño físico del


arreglo es 10

índices Algoritmos y Estructuras de Datos 2021


Trabajo Práctico 2
Encapsulamiento y abstracción con Listas sin orden

Referencias
clase abstracta (letra cursiva)
clase concreta
método público abstracto (+)
método público concreto (+)
atributo privado (-)
Trabajo Práctico 2
Encapsulamiento y abstracción
La clase abstracta ListaDeEnteros
package tp03.ejercicio2;
public abstract class ListaDeEnteros {
public abstract void comenzar();
public abstract Integer proximo();
public abstract boolean fin();

public abstract Integer elemento(int pos);

public abstract boolean agregarEn(Integer elem, int pos);


public abstract boolean agregarInicio(Integer elem);
public abstract boolean agregarFinal(Integer elem);

public abstract boolean eliminar(Integer elem);


public abstract boolean eliminarEn(int pos);

public abstract boolean incluye(Integer elem);


public abstract boolean esVacia();
public abstract int tamanio();
}

¿Qué mecanismos podemos usar para crear subclases concretas de Lista?

n
ul
Trabajo Práctico 2
Encapsulamiento y abstracción
Lista de enteros implementada con un arreglo
public class ListaDeEnterosConArreglos extends ListaDeEnteros {
private int tamanio;
private int[] datos = new int[200];
private int actual = 0;
@Override
public void comenzar() {
actual = 0;
}
@Override
public Integer proximo() {
return datos[actual++];
}
@Override
public boolean fin() { l.comenzar();
return actual==tamanio;
}
@Override
public Integer elemento(int pos) {
return datos[pos-1];
}
@Override
public boolean agregarEn(Integer elem, int pos) {
if (pos<1 || pos>tamanio+1 || pos>datos.length || tamanio==datos.length)
return false;
tamanio++;
for (int i = tamanio; i >= pos; i--)
datos[i] = datos[i - 1];
datos[pos-1] = elem; NOTA: @override indica que se está
return true; sobrescribiendo un método de la superclase y el
} compilador informa un error en caso de no exisitir el
. . .} método en la superclase
Algoritmos y Estructuras de Datos 2021
Trabajo Práctico 2
Encapsulamiento y abstracción
Lista de enteros implementada con nodos enlazados
public class ListaDeEnterosEnlazada extends ListaDeEnteros {
Por ejemplo podría
private NodoEntero inicio; referenciar a este nodo
private NodoEntero actual;
private NodoEntero fin;
private int tamanio;
@Override public class NodoEntero {
public void comenzar() { private Integer dato;
actual = inicio; private NodoEntero siguiente;
} public Integer getDato() {
@Override return dato;
public Integer proximo() { }
Integer elto = actual.getDato(); public void setDato(Integer dato) {
actual = actual.getSiguiente(); this.dato = dato;
return elto; }
} public NodoEntero getSiguiente() {
@Override return siguiente;
public boolean fin() { }
return (actual==null); public void setSiguiente(NodoEntero siguiente){
} this.siguiente = siguiente;
@Override }
public boolean incluye(Integer elem) { }
NodoEntero n = this.inicio;
while (!(n == null) && !(n.getDato().equals(elem))) El uso es igual a la de Lista con arreglos, solo se cambia la
n = n.getSiguiente(); instanciación. La clases concretas no agregan métodos nuevo, por ello
return !(n == null); los métodos que se pueden invocar son los definidos en la clase
} abstracta.
@Override
public boolean esVacia() {
return (inicio == null);
}
. . . }
Algoritmos y Estructuras de Datos 2021
Trabajo Práctico 2
Encapsulamiento y abstracción
Ejemplo de uso de una lista desde otra clase que está en otro paquete.
package tp03.ejercicio2;
import tp03.ejercicio1.ListaDeEnteros;
import tp03.ejercicio1.ListaDeEnterosEnlazada;

public class PilaDeEnteros {


private ListaDeEnteros datos =
new ListaDeEnterosEnlazada();

public void apilar(int dato) {


datos.agregarEn(dato, 1);
}

public int desapilar() {


int x = datos.elemento(1);
datos.eliminarEn(1);
return x;
}

public int tope() {


return datos.elemento(1);
}

public boolean esVacia() {


return datos.tamanio()==0;
}
}

La salida es: Tope: 30


Trabajo Práctico 2
Encapsulamiento y abstracción
A continuación se muestra la clase Lista donde se pueden mantener elementos de tipo Object. Se podrán
definir dos subclases ListaConArreglos y ListaEnlazada de manera que también puedan almacenar
elementos de tipo Object. package tp03.ejerciciox;
public abstract class Lista {
public abstract void comenzar();
public abstract Object proximo();
public abstract boolean fin();

public abstract Object elemento(int pos);

public abstract boolean agregarEn(Object elem, int pos);


public abstract boolean agregarInicio(Object elem);
public abstract boolean agregarFinal(Object elem);

public abstract boolean eliminar(Object elem);


public abstract boolean eliminarEn(int pos);

public abstract boolean incluye(Object elem);


public abstract boolean esVacia();
public abstract int tamanio();
}
Ejemplo de uso:
ListaConArreglos lista = new ListaConArreglos();
lista.agregarEn(new Integer(2), 1); - ¿Podría guardar objetos de tipo ¿Alumno?
lista.agregarEn(new Integer(4), 2);
lista.agregarEn(new String(“Hola”),3);
- Y al recuperarlo, ¿puedo pedirle directamente
su número de alumno?
Integer x = (Integer)lista.elemento(2); // se debe castear
Generalizando Estructuras
Analizamos la implementación de Listas con elementos de tipo Integer y con elementos de tipo Object:
Usando un tipo específico (Integer): Ventajas: el compilador chequea
el tipo de dato que se
public class ListaDeEnterosConArreglos { inserta. No se necesita hacer uso del
casting
private Integer[] datos = new Integer[200]; Desventajas: si se quisiera tener
private int actual; una estructura para cada
tipo de datos, se debería definir una
. . . clase para cada tipo. Por
} ejemplo: ListaDeEnteros, List
aDeAlumnos, etc.

ListaDeEnterosConArreglos lista = new ListaDeEnterosConArreglos();


lista.agregarFinal( new Integer(50));
lista.agregarFinal( new String(“Hola”)); 🡺 no deja poner otra cosa que no sea Integer
Integer x1 = lista.elemento(1); 🡺 no necesitamos castear cada vez

Usando Object:
Ventajas: Se logra una
public class ListaConArreglos { estructura genérica
private Object[] datos = new Object[200]; Desventajas: El com
pilador pierde la opor
private int actual; realizar chequeos y se de tunidad de
. . . be hacer uso de casting
}

ListaConArreglos lista = new ListaConArreglos();


lista.agregarFinal(new Integer(50));
lista.agregarFinal(new String(“Hola”)); 🡺 deja poner cualquier tipo
Integer x = (Integer)lista.elemento(1); 🡺 necesitamos castear y podría dar error
en ejecución
Generalizando Estructuras
J2SE 5.0 introduce varias extensiones al lenguaje java. Una de las más importantes, es la incorporación de los
tipos genéricos, que le permiten al programador abstraerse de los tipos.
Usando tipos genéricos, es posible definir estructuras dónde la especificación del tipo de objeto a guardar se
posterga hasta el momento de la instanciación.
package tp03.ejercicio6;
Para especificar el uso de genéricos, se utiliza <tipo>. public class NodoGenerico<T> {
package tp03.ejercicio6; private T dato;
public class ListaEnlazadaGenerica<T> extends ListaGenerica<T>{ private NodoGenerico<T> siguiente;
private NodoGenerico<T> inicio;
private NodoGenerico<T> actual; public T getDato() {
private NodoGenerico<T> fin; return dato;
private int tamanio; }
... . . .
} }

Cuando se instancian las estructuras se debe definir el tipo de los objetos que en ella se almacenarán:
ListaEnlazadaGenerica<Integer> lista = new ListaEnlazadaGenerica<Integer>();
lista.agregarFinal(new Integer(50));
lista.agregarFinal(new String(“Hola”)); 🡺 error de compilación
lista.comenzar();
Integer x = lista.proximo(); 🡺 no necesitamos castear

ListaEnlazadaGenerica<Alumno> lista = new ListaEnlazadaGenerica<Alumno>();


lista.agregarFinal(new Alumno(“Peres, Juan”, 3459);
lista.agregarFinal(new Alumno(“Rios, Ivana”, 3052);

lista.comenzar();
Alumno a = lista.proximo(); 🡺 no necesitamos castear

Integer i = lista.proximo(); 🡺 error en compilación


lista.agregarFinal(55); 🡺 error de compilación
¿Cómo quedan las Listas con Tipos Genéricos?
Clase abstracta ListaGenerica y una subclases implementada como lista enlazada con tipos Genéricos:

package tp03.ejercicio6; package tp03.ejercicio6;

public abstract class ListaGenerica<T> { public class ListaEnlazadaGenerica<T> extends


public abstract void comenzar(); ListaGenerica<T> {
public abstract T proximo(); private NodoGenerico<T> inicio;
public abstract boolean fin(); private NodoGenerico<T> actual;
private NodoGenerico<T> fin;
public abstract T elemento(int pos); private int tamanio;
public abstract boolean agregarEn(T elem, int pos);
public abstract boolean agregarInicio(T elem); @Override
public abstract boolean agregarFinal(T elem); public void comenzar() {
actual = inicio;
public abstract boolean eliminar(T elem); }
public abstract boolean eliminarEn(int pos); @Override
public T proximo() {
public abstract boolean incluye(T elem); T elto = actual.getDato();
public abstract boolean esVacia(); actual = actual.getSiguiente();
public abstract int tamanio(); return elto;
} }
...
package tp03.ejercicio6;
}
public class NodoGenerico<T> {
private T dato;
private NodoGenerico<T> siguiente;

public T getDato() {
return dato;
}
. . .
}

También podría gustarte