Programación orientada a objetos: listas

Programación orientada a objetos: listas

Seguimos con nuestro curso de programación, en este caso vamos a ver las listas como primera estructura de datos en Java. Las estructuras de datos son almacenes donde almacenar información. Esta información son los tipos de Java, ya sean los primitivos como los tipos definidos por nosotros. Por ejemplo, podemos definir las siguientes estructuras:

listas

private int[] estructuraEnteros;private int[] estructuraString;private Granja[][] estructuraGranja;

Estas estructuras tan simples son las que definimos nosotros, los usuarios y son las denominadas listas de elementos o array. Son estructuras lineales, es decir, para buscar un elemento tenemos que recorrer toda la lista mirando de forma consecutiva todos los elementos hasta encontrar el que buscamos. Podemos añadir elementos a la estructura de la siguiente forma:

public void ejemplo(){    estructuraEnteros[0] = 1;    estructuraEnteros[1] = 2;    estructuraString[0] = "Maria";    estructuraString[1] = "Pepe";    System.out.println(""+estructuraEnteros[0]);}

Ejecutando este código veremos cómo dará un error. Todas las estructuras de datos se deben inicializar, es decir, crear el objeto que en el albergará los objetos que añadíamos, instanciarlo.

public void ejemplo2(){         // inicializamos las estruturas con un tamaño    estructuraEnteros = new int[2];    estructuraString = new String[2];       estructuraEnteros[0] = 1;    estructuraEnteros[1] = 2;    estructuraString[0] = "Maria";    estructuraString[1] = "Pepe";       System.out.println(""+estructuraEnteros[0]);}

Este último código si funcionará, pero si por ejemplo ejecutamos:

public void ejemplo3(){    estructuraEnteros = new int[2];    estructuraString = new String[2];    estructuraString[3] = "Pepe"; // linea 1    System.out.println(""+estructuraEnteros[0]); //linea 2    System.out.println(""+estructuraEnteros[4]); //linea 3}

Tendremos un par de errores, en concreto si nos fijamos en:

  • Linea 1: dará error porque en esa posición 3 se sale del tamaño de la estructura.
  • Linea 2: dará error porque no hemos metido nada en la posición 0.
  • Linea 3: dará error por los dos motivos anteriores.

La solución a estos problemas puede ser:

public void ejemplo3Solucion(){    estructuraEnteros = new Integer[2];    estructuraString = new String[2];    estructuraString = new String[4]; //solucion 1     estructuraString[3] = "Pepe"; // linea 1    estructuraString = new String[5]; // solucion 3    estructuraEnteros[0] = 10; // solucion 2    System.out.println(""+estructuraEnteros[0]); //linea 2}

Antes de continuar es necesario aclarar la consideración. Se redimensiona antes la estructura porque si se añade un elemento y luego se redimensiona de esta forma todo el contenido de dentro se borrará. Todo esto lo podemos resumir en un ejemplo final:

public void ejemplo4(){estructuraGranja = new Granja[10][10];System.out.println("N de filas: "+estructuraGranja.length);System.out.println("N de columnas:"+estructuraGranja[0].length);estructuraGranja[0][0] = new Granja("Granja Pepe");}

En este ejemplo final introducimos la idea de una estructura bidimensional, una matriz. Su representación gráfica es un tablero. Además del atributo length que viene por defecto en todas las estructuras de datos definidas de esta manera y lo que hace es devolver el tamaño de la estructura seleccionada.

Listas predefinidas

Hasta ahora hemos estado trabajando con listas creadas y gestionadas por nosotros mismos, que funcionan, que tienen un correcto funcionamiento, pero que son realmente pesadas a la hora de utlizarlas. Por ejemplo: cada vez que metamos un nuevo dato en la lista tenemos que indicarle en que posición lo queremos meter y además estar pendientes de no pasarnos del tamaño de la lista.

ArrayList

En Java tenemos la clase ArrayList que nos trae todas estas funciones ya implementadas y que, por ejemplo, para añadir un dato a una lista simplemente tenemos que llamar a un método que pasándole por parámetro el dato el método se ocupe de meter el dato en la lista.

Vamos a ilustrar lo anterior con un ejemplo. Lo primero que tenemos que hacer es importar la clase que utilizaremos, porque si, ArrayList es una clase que nosotros la instanciaremos como un objeto. Para hacer el import añadimos el siguiente código al principio del todo, antes de definir la clase:

import java.util.ArrayList;

Definimos el nuevo atributo:

ArrayList array = new ArrayList();

Y un nuevo método que ilustre el ejemplo:

void ejemploAñadir(int i){    array.add(i);}

Si estamos usando una IDE como Eclipse, veremos que el compilador se queja, el código funcionará, no dará error, pero nos muestra un aviso:

warning_arraylist

Esto quiere decir que el ArrayList que hemos definido debería estar parametrizado, algo difícil de explicar pero que podemos traducir como que el ArrayList solo debería aceptar un tipo, que de no hacerlo es probable que tengamos problemas.

¿Qué problemas? pues sencillo, si no parametrizamos, si no definimos que tipo de elementos podremos añadir podremos añadir cualquier tipo, y si por ejemplo en una lista que solo debería tener personas añadimos granjas, cuando leamos de esa lista e intentemos operar con ella nos dará problemas.

Por eso, siempre debemos parametrizar las listas, aunque esa con el tipo Object con este tipo podemos añadir elementos de cualquier tipo, ya que todos los tipos heredan de este tipo, pero ya lo explicaremos.

Vamos a ver como parametrizar un un ArrayList. Supongamos una lista de enteros, esta lista deberá estar parametrizada como un int, la definimos como:

ArrayList<int> listaEnteros = new ArrayList<int>();

tipos_envolventes

Pero sorpresa, esto no funcionará, ¿por qué?, los ArrayList solo los podemos parametrizar con objetos que se puedan instanciar, y recordemos int es un tipo primitivo, por tanto, no se puede instanciar. Debemos por tanto buscar una forma de hacer una lista que solo acepte enteros, aquí surgen los tipos envolventes, que por ahora no nos interesan mucho lo que son, simplemente que nos ayudaran a resolver estos problemas. Los tipos envolventes presentes en el lenguaje Java son uno por uno por cada tipo primitivo. Podemos resumirlos en:

Si nos fijamos el tipo String que usamos y que consideramos tipo primitivo es un tipo envolvente, esto quiere decir que podemos definir y usar los tipos envolventes de una forma similar a como hacemos con los tipos primitivos.

Continuemos con el ejemplo, y redefinamos el ArrayList como:

ArrayList<Integer> listaEnteros = new ArrayList<Integer>();

y un método donde probar su funcionalidad como:

void ejemploInteger(int i){    listaEnteros.add(i);}

Si nos fijamos Eclipse ya no nos avisará con ningún otro warning relacionado con esto.

En los ejemplos anteriores vemos las operaciones más sencillas que podemos hacer pero hay más. ArrayList sigue siendo una estructura lineal, hay más tipos de listas en Java, pero por ahora nos quedaremos con esta.

Para probarlo vosotros mismos podéis descargar el código fuente que hemos utilizado para la ocasión.

Para ti
Queremos saber tu opinión. ¡Comenta!