Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Colecciones de Datos
En este caso, Clase tiene un miembro llamado miColeccion, que es una colección
(un ArrayList) de objetos de clase TipoElemento. Esta forma, más explícita en cuanto
a lo que se intentará escribir como código, tiene la desventaja de que queda más
“atada” a la implementación pues obliga a que esté, sí o sí, implementada con un
ArrayList.
La otra forma de representar esta relación cuando la colección es atributo de una
clase es la siguiente:
Esta forma es más corta y es la más usada, ya que no está explícitamente atada a la
implementación con ArrayList. Muy pronto veremos que hay otras estructuras múltiples
que se pueden describir en UML de la misma manera o de forma muy similar.
Tal como puede verse en la relación entre las clases, el asterisco representa una
cantidad indeterminada de elementos, que en el caso de los ArrayList es dinámica.
permiten manipular su contenido sino que también nos permiten saber su estado en
cuanto a la cantidad de elementos que la componen.
A continuación aparecen los métodos que más usaremos (hay más, pero por ahora
no los trataremos):
En Java los ArrayList son una implementación especial de List, y por eso también se
los conoce como Listas. No obstante este concepto es más vasto de lo que trataremos
aquí, donde sólo los utilizaremos para crear colecciones dinámicas de datos. Por otro
lado, ese nombre lo usaremos más adelante en el cuatrimestre para referirnos a una
estructura específica.
Creación de un ArrayList
Como primera medida se debe importar el paquete correspondiente los ArrayList a
partir de la adición de su namespace:
import java.utils.ArrayList;
Así, para crear una colección de objetos de la clase Persona, por ejemplo los contactos
de una agenda, haremos:
System.out.println(coleccion.size());
Antes dijimos que esta estructura sólo maneja objetos. En caso de que se necesite
crear una colección de elementos de los tipos nativos del lenguaje (integer, double,
etc.) debemos recurrir a sus contrapartes como clase, conocidas como wrapper classes
o clases envoltorio:
Recordemos que String es una clase. Por lo tanto se pueden crear ArrayLists de
cadenas de caracteres directamente:
En el primer caso siempre deberá declararse entre los atributos de la clase y crearse
dentro del constructor de la clase. No debe declararse dentro del constructor ya que
de esa forma sería una variable local y desaparecería al salir del constructor, y se
crea dentro del mismo porque es el único método que se ejecutará indefectible e
inmediatamente al crear la clase que contiene la colección. También debe tenerse
en cuenta que la colección puede ser creada pero que puede permanecer vacía hasta
el momento en el cual se le agregue algún elemento.
// creamos el objeto
Objeto elemento = new Objeto();
...
...
...
// lo agregamos a la colección
coleccion.add(elemento);
Solamente en el caso de las clases relacionadas a los tipos nativos (int, double, char,
boolean) podremos agregar elementos sin necesidad de crear explícitamente el objeto
(Java lo hará por nosotros):
También se puede pasar un primer valor adicional, numérico, que indique en qué
posición de la colección se desea insertar el nuevo elemento. Por ejemplo…
caso de poner en un arraylist valores con null primero hay que chequear si es null y
luego usarlo. Por lo tanto se aconseja usar null como elemento en casos muy especiales.
Esto devolverá la referencia al elemento sin quitarlo de la lista (no hace una copia).
Entonces, si modificamos el elemento que tenemos en el auxiliar, también se verá
modificado en la lista, pues es el mismo elemento referenciado desde dos lugares
distintos.
o, directamente:
coleccion.remove(0);
La diferencia entre estos dos casos es que mientras el primero guarda el elemento
removido en una variable auxiliar para su uso posterior, el segundo lo descarta.
También se puede intentar la remoción de un elemento a partir del mismo (es
decir que, en vez de pasar como parámetro la posición del elemento a extraer, se pasa
el elemento). Esto suele ser útil cuando ya tenemos el elemento, por ejemplo porque
otro método lo buscó, y queremos extraerlo del arraylist sin saber su posición en el
mismo (y ni siquiera saber fehacientemente si está).
coleccion.remove(miElemento);
o, mejor…
Este ejemplo podría leerse como “para cada persona que esté en la colección de
personas, mostrar el nombre y el número de documento”. Esto hará que en cada
iteración (en cada vuelta del ciclo) la variable persona guarde temporalmente, una a
una, cada persona que esté en la estructura, comenzando con la primera de todas y
hasta que no haya más. La variable persona tendrá asignada en cada ciclo, entonces,
el objeto de la colección que se está visitando en ese momento.
El ejemplo anterior utilizará el ciclo while para recorrer la estructura mientras haga
falta. El if interno, como está expresado en los comentarios, cumple dos tareas. La
primera es asignar el elemento al auxiliar cuando es el que buscamos. La segunda, es
darnos la posibilidad de intentar con el siguiente, a ver si es el que queremos. El
incremento de índice puede hacerse también fuera del if (no en el else), aunque en
ese caso perdería la posición donde encontró el elemento. De esta forma, guarda
también la posición y no incremente el índice sin necesidad.
Sin embargo esto mismo se puede hacer de una forma más elegante, más clara y
más propia de un programa orientado a objetos, pues deja la responsabilidad de
identificar el elemento que queremos encontrar a la clase que corresponde. Para esto
debemos separar el código en dos partes: por un lado crear un método en la clase
Persona que podría llamarse, en este caso, mismoDocumento(documento) cuya función
Al salir del ciclo el valor de indice puede ser igual al size() de la colección o menor. Si
vale lo mismo que size() significa que el elemento buscado no fue hallado. Si vale
cualquier otra cosa, en esa posición de la colección tendremos lo que estábamos
buscando. Entonces hacemos:
1, 7, 9, 17, 22
Seguiremos parados en la posición 2, donde ahora, en vez del 4 que extrajimos, está el
9. Gracias a que no avanzamos, en la nueva iteración del ciclo (donde podría haber
encontrado un nuevo número par) trataremos el 9, luego el 17 y así hasta llegar al 22.
Aquí también nos detendremos a extraer el número y no incrementaremos, pero la
lista habrá perdido un nuevo elemento (el 22), y quedarán sólo con 4 elementos (1, 7,
9, 17). Como el ciclo sólo itera mientras el índice sea menor a la cantidad de
elementos de la colección, saldremos y la lista quedará solamente con los números
impares.
public Club() {
this.socios = new ArrayList<Socio>();
}
También podemos ver dos métodos distintos para agregar socios, el primero pasándole
directamente un objeto de la clase Socio, y el segundo que sólo recibe el nombre del
nuevo socio, que será instanciado y agregado en el momento (sobrecarga).
¿Y qué deberíamos hacer para dar de baja un socio? ¿Cómo hacemos para devolver
la instancia de socio que queremos eliminar sin exponer la colección completa? Tal vez
podríamos hacer algo como lo que sigue:
.. o aún una versión más resumida que no requiere crear una variable auxiliar:
En este caso agregará a la colección vitalicios (creada como variable local) todos
aquellos socios que cumplan con la condición de ser vitalicios.
En este caso, donde los mismos objetos que se encuentran en el arraylist original se
insertan en el arraylist secundario que será devuelto por el método y por lo tanto
compartido, corremos ciertos riesgos de exposición de datos (un caso similar a cuando
nos pasan objetos desde el exterior de la clase y los insertamos directamente).
Una de las formas de solucionar el problema es evaluar, a la hora de devolver un
elemento, si realmente hay que devolver ese elemento, su contenido, o un objeto
ad-hoc creado sólo con los datos necesarios y sin métodos (o sólo con los necesarios).
De esa manera, al crear nuevos objetos que son los que se devolverán, nuestros datos
quedan protegidos.