Genericos en Java

java_base_web

Hola a todos, hoy explicare que son los genéricos y para que se usan en Java.

Los genéricos nos indica que tipo de datos puede manejar una estructura de datos, como una lista enlazada. Es lo que se conoce como clases parametrizadas, donde le indicamos con una clase entre <>.

En principio, no es estrictamente necesario que una clase parametrizada, se le indique una clase, permitiéndonos añadir varios tipos de valores pero esto nos dará muchos problemas en el futuro, ya que para acceder a un nodo de esta lista se debe hacer un casting del mismo tipo para que pueda ser accedido.

Vamos a ver un simple ejemplo:

import java.util.ArrayList;
public class ArrayListApp {

	public static void main(String[] args) {

		ArrayList<String> listaParametrizada=new ArrayList<>();
		ArrayList listaNoParametrizada=new ArrayList();

		//Solo podemos insertar String
		listaParametrizada.add("hola");
		listaParametrizada.add("adios");
		listaParametrizada.add(new Integer(5)); //Nos dara un error

		//Podemos insertar cualquier tipo de valor
		listaNoParametrizada.add(new Integer(3));
		listaNoParametrizada.add("¿Como vas?");

		//No es necesario hacer un casting
		String v1=listaParametrizada.get(0);
		String v2=listaParametrizada.get(0);

		//Es necesario hacer un casting
		int v3=(int)listaNoParametrizada.get(0);
		String v4=(String)listaNoParametrizada.get(1);
	}

}

También se pueden hacer métodos y clases genéricas.

Mira este ejemplo de nuestra ListaEnlazada:

/**
 *
 * @author DiscoDurodeRoer
 * @param <T>
 */
public class Nodo<T> {
   
    private T dato;
    private Nodo<T> siguiente;

    /**
     * Constructor por defecto
     */
    public Nodo(){
        siguiente=null;
     }

    /**
     * Le pasamos un dato al nodo
     * @param p 
     */
    public Nodo(T p){
        siguiente=null;
        dato = p;
    }

    /**
     * Le pasamos un dato y su siguiente nodo al nodo
     * @param t Dato a insertar
     * @param siguiente Su sisguiente nodo
     */
    public Nodo(T t, Nodo<T> siguiente){
        this.siguiente=siguiente;
        dato = t;
    }
    
    public T getDato() {
        return dato;
    }

    public void setDato(T dato) {
        this.dato = dato;
    }

    public Nodo<T> getSiguiente() {
        return siguiente;
    }

    public void setSiguiente(Nodo<T> siguiente) {
        this.siguiente = siguiente;
    }
    
}

Ahora, vamos con la clase ListaEnlazada.


/**
 * @author DiscoDurodeRoer
 * @param <T>
 * Lista enlazada simple
 */
public class ListaEnlazada<T>{
   
    //Atributos
    private Nodo<T> primero;

    /**
     * Constructor por defecto
     */
    public ListaEnlazada(){
        listaVacia();
    }

    /**
     * Vacia la lista
     */
    private void listaVacia(){
        primero = null;
    }

    /**
     * Indica si la lista esta vacia o no
     * @return True = esta vacia
     */
    public boolean estaVacia(){
        return primero == null;
    }

    /**
     * Inserta un objeto al principio de la lista
     * @param t Dato insertado
     */
    public void insertarPrimero(T t){
        Nodo<T> nuevo = new Nodo<>(t);

        if (!estaVacia()){
            //Sino esta vacia, el primero actual pasa a ser
            // el siguiente de nuestro nuevo nodo
            nuevo.setSiguiente(primero);
        }
        
        //el primero apunta al nodo nuevo
        primero=nuevo;
        
    }

    /**
     * Inserta al final de la lista un objeto
     * @param t Dato insertado
     */
    public void insertarUltimo(T t){

        Nodo<T> aux = new Nodo<>(t);
        Nodo<T> rec_aux;

        if (estaVacia()) {
            insertarPrimero(t);
        }else {
            rec_aux = primero;
            
            //Buscamos el ultimo nodo
            while(rec_aux.getSiguiente() != null){
                rec_aux=rec_aux.getSiguiente();
            } 
                
            //Actualizamos el siguiente del ultimo
            rec_aux.setSiguiente(aux);
        }
    }

    /**
     * Quita el primer elemento de la lista
     */
    public void quitarPrimero(){
        Nodo<T> aux;
        if (!estaVacia()){
            aux=primero;
            primero = primero.getSiguiente();
            aux=null; //Lo marcamos para el recolector de basura
        }
    }

    /**
     * Quita el ultimo elemento de la lista
     */
    public void quitarUltimo(){
        Nodo<T> aux=primero;
        if(aux.getSiguiente()==null)
           //Aqi entra, si la lista tiene un elemento
           listaVacia();
        if(!estaVacia()) {
            aux=primero;
            
            //Buscamos el penultimo, por eso hay dos getSiguiente()
            while(aux.getSiguiente().getSiguiente() != null){
                aux=aux.getSiguiente();
            }
            
            //Marcamos el siguiente del antepenultimo como nulo, eliminando el ultimo
            aux.setSiguiente(null);
        }

    }        

    /**
     * Devuelve el último elemento de la lista
     * @return Último elemento
     */
    public T devolverUltimo(){
        T elemen = null;
        Nodo<T> aux;
        if (!estaVacia()){
            aux = primero;
            
            //Recorremos
            while(aux.getSiguiente() != null){
                aux = aux.getSiguiente();
            }
            elemen = aux.getDato();
        }
        return elemen;
    }

    /**
     * Devuelve el primer elemento de la lista
     * @return Primer elemento, null si esta vacia
     */
    public T devolverPrimero(){
        T elemen = null;
        if (!estaVacia()){
            elemen = primero.getDato();
        }
        return  elemen;
    }

    /**
     * Devuelve el número de elementos de la lista
     * @return Número de elementos
     */
    public int cuantosElementos(){
        Nodo<T> aux;
        int numElementos=0;
        aux = primero;

        //Recorremos
        while(aux != null){
            numElementos++;
            aux = aux.getSiguiente();
        }
        return numElementos;

    }
    
    /**
     * Devuelve el dato del nodo en la posicion pos
     * @param pos
     * @return dato del nodo en la posicion indicada
     */
    public T devolverDato(int pos){
        Nodo<T> aux=primero;
        int cont=0;
        T dato=null;
        
        if(pos<0 || pos>=cuantosElementos()){
            System.out.println("La posicion insertada no es correcta");
        }else{
            //recorremos
            while(aux!=null){
                if (pos == cont){
                    //Cogemos el dato
                    dato=aux.getDato();
                }
                
                aux=aux.getSiguiente();
                cont++;
                
            }
        }
        
        return dato;
        
    }
    
    /**
     * Devuelve el nodo de la posicion indicada
     * @param pos
     * @return Nodo de la posicion indicada
     */
    public Nodo<T> devolverNodo(int pos){
        Nodo<T> aux=primero;
        int cont=0;
        
        if(pos<0 || pos>=cuantosElementos()){
            System.out.println("La posicion insertada no es correcta");
        }else{
            //recorremos
            while(aux!=null){
                if (pos == cont){
                    //Devuelvo aux, con esto salimos de la función
                    return aux; 
                }
                
                //Actualizo el siguiente
                aux=aux.getSiguiente();
                cont++;
                
            }
        }
        
        return aux;
        
    }
    
    /**
     * Inserta un nuevo nodo en la posicion indicada con el su dato
     * @param pos
     * @param dato 
     */
    public void introducirDato(int pos, T dato){
        Nodo<T> aux=primero;
        Nodo<T> auxDato=null; //Debemos crear un nodo para insetar el dato
        Nodo<T> anterior=primero; //Debemos crear un nodo para insetar el dato
        
        int contador=0;
        
        if(pos<0 || pos>cuantosElementos()){
            System.out.println("La posicion insertada no es correcta");
        }else{
            
            if(pos==0){
                insertarPrimero(dato);
            }else if(pos==cuantosElementos()){
                insertarUltimo(dato);
            }else{
                //Recorremos
                while(aux!=null){
                    if (pos == contador){
                        //Creo el nodo
                        auxDato=new Nodo<>(dato, aux);
                        //El siguiente del anterior a aux es auxDato
                        anterior.setSiguiente(auxDato);
                    }
                    
                    //Actualizo anterior
                    anterior=aux;
                    
                    contador++;
                    aux=aux.getSiguiente(); //Actualizo siguiente
                }
            }
        }
        
    }
    
    /**
     * Modifica el dato indicado en el nodo de la posicion indicada
     * @param pos
     * @param dato 
     */
    public void modificarDato(int pos, T dato){
        Nodo<T> aux=primero;
        int cont=0;
        
        if(pos<0 || pos>=cuantosElementos()){
            System.out.println("La posicion insertada no es correcta");
        }else{
            //Recorremos
            while(aux!=null){
                if (pos == cont){
                    //Modificamos el dato directamente
                    aux.setDato(dato); 
                }
                cont++;
                aux=aux.getSiguiente(); //Actualizamos
            }
        }
        
    }

    /**
     * Borra un elemento de la lista
     * @param pos Posición de la lista que queremos borrar
     */
    public void borraPosicion(int pos){

        Nodo<T> aux=primero;
        Nodo<T> anterior=null;
        int contador=0;

        if(pos<0 || pos>=cuantosElementos()){
            System.out.println("La posicion insertada no es correcta");
        }else{
            while(aux!=null){
                if (pos == contador){
                    if (anterior==null){
                        primero = primero.getSiguiente();
                    }else {
                        //Actualizamos el anterior
                        anterior.setSiguiente(aux.getSiguiente());
                    }
                    aux=null;
                }else{
                    anterior=aux;
                    aux=aux.getSiguiente();
                    contador++;
                }
            }
        }
    }

    /**
     * Devuelve el primer el elemento y lo borra de la lista
     * @return Primer elemento
     */
    public T devolverYBorrarPrimero(){

        T dato=devolverPrimero();
        quitarPrimero();
        return dato;
    }

    /**
     * Indica la posición del primer dato que se encuentre
     * @param t dato buscado
     * @return Posición del dato buscado, -1 si no se encuentra o esta vacia
     */
    public int indexOf (T t){

       Nodo<T> aux=primero;
       if (estaVacia()){
            return -1;
       }else{
           int contador=0;
           boolean encontrado=false;
           
            //recorremos, cuando encontrado=true, sale del bucle
           while(aux!=null && !encontrado){
               if(t.equals(aux.getDato())){
                   //Cambiamos a true
                   encontrado=true;
               }else{
                    contador++;
                    //actualizamos
                    aux=aux.getSiguiente(); 
               }
           }
           if(encontrado){
                return contador;
           }else{
                //no se ha encontrado
                return -1;
           }
       }
    }
    
    /**
     * Indica la posición del primer dato desde la posicion indicada
     * @param t dato buscado
     * @param pos
     * @return Posición del dato buscado, -1 si no se encuentra o esta vacia
     */
    public int indexOf (T t, int pos){

       Nodo<T> aux;
       if (estaVacia()){
            return -1;
       }else{
           int contador=pos;
           boolean encontrado=false;
           
           //Empezamos desde el nodo correspondiente
           aux=devolverNodo(pos);
           
           //recorremos, cuando encontrado=true, sale del bucle
            while(aux!=null && !encontrado){
               if(t.equals(aux.getDato())){
                   //Cambiamos a true
                   encontrado=true;
               }else{
                    contador++;
                    //Actualizamos
                    aux=aux.getSiguiente();
               }
            }
            if(encontrado){
                return contador;
            }else{
                return -1;
            }
       }
    }

    /**
     * Indica si un dato existe en la lista
     * @param t Dato a comprobar
     * @return Si el dato existe, devuelve true
     */
    public boolean datoExistente(T t){

        boolean existe=false;

        Nodo<T> aux=primero;

        while(aux!=null && !existe){

            if(aux.getDato().equals(t)){
                existe=true;
            }
            
            //Actualizamos
            aux=aux.getSiguiente();
        }

        return existe;
    }
    
    /**
     * Muestra el contenido de la lista
     */
    public void mostrar(){
        System.out.println("Contenido de la lista");
        System.out.println("---------------------");
        
        Nodo<T> aux=primero;
        
        while(aux!=null){
            System.out.println(aux.getDato());//mostramos el dato
            aux=aux.getSiguiente();
        }
        
    }
    
    /**
     * Devuelve el contenido de la lista en un String
     * @return contenido de la lista
     */
    @Override
    public String toString(){
        
        String contenido="";
        Nodo<T> aux=primero;
        
        while(aux!=null){
            contenido=aux.getDato()+"\n"; //guardamos el dato
            aux=aux.getSiguiente();
        }
        
        return contenido;
    }

}

Fijate que hace el mismo efecto que en el ejemplo anterior con ArrayList.

Espero que os sea de ayuda. Si tenéis dudas, preguntad. Estamos para ayudarte.

Etiquetas

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *