gravatar

07 Curso de Java OO. Colecciones de objetos

Resumen:   Se estudiara el uso de colecciones de objetos y una técnica de ordenación mediante interfaces.

1. LA CLASE OBJECT
Todas las clases en java heredan de la clase java.lang.Object.
Los siguientes métodos se heredan de la clase Object

boolean equals(Object obj) Indica si otro objeto es igual a otro.
int hashcode() Proporciona un valor hashcode para el objeto (id)
String toString() Proporciona una representación en cadena del objeto

1.2. Convertir primitivas en referencias
Las primitivas no se comparan con null.
Las primitivas no pueden integrar una Colección.
Para cada primitiva java provee un clase para convertirlo en referencia y tratarlo como un objeto y resolver los problemas previos.

String cadena = String.valueOf(1024);
int entero = Integer.parseInt(cadena);
Integer objetoPrecio = new Integer(25);
int enteroPrecio = objetoPrecio.intValue();
String cadenaPrecio = objetoPrecio.toString();

2. COLECCIONES

Java provee un conjunto librerías para manipular y almacenar datos.
Estas librerías se llaman colecciones.
Las colecciones se organizan en:
- Interfaces: Manipulan los datos independientemente de los detalles de implementación.
- Clases: Implementan las interfaces.
Para programar con colecciones se debe:
- Elegir una interfaz adecuada a la funcionalidad requerida.
- Elegir una clase que implemente la interfaz
- Extender la clase si fuera necesario.

En que se diferencia una clase de una interface?

2.1. Arquitectura.

Las interfaces y las clases están relacionadas en un armazón (framework) de colecciones para facilitar su uso.
- Interfaces de colecciones que son definiciones abstractas de los tipos de colecciones.
- Clases que implementan las interfaces.
- Clases abstractas que implementan parcialmente las interfaces.
- Métodos estáticos que son algoritmos (por ejemplo ordenar una lista).
- Interfaces de soporte para las colecciones. (una infraestructura).

2.2. Interfaces de colecciones

Interface
Collection. Representa un grupo de objetos. Sin implementaciones directas, agrupa la funcionalidad general que todas las colecciones ofrecen.
Set. Colección que no puede tener objetos duplicados.
SortedSet . Set que mantiene los elementos ordenados
List. Colección ordenada que puede tener objetos duplicados
Map. Colección que enlaza claves y valores; no puede tener claves duplicadas y cada clave debe tener al menos un valor.
SortedMap. Map que mantiene las claves ordenadas.

2.2.1. La interface Collection. La interfase raiz de las colecciones.
2.2.2. La interface List. Colecciones ordenadas (secuencias) en las que cada elemento ocupa una posición identificada por un índice. El primer índice es el 0. Las listas admiten duplicados.
2.2.3. La interface Map. Son pares de datos(clave, valor). No puede haber claves duplicadas y cada clave se corresponde con al menos un valor.

3. Ejemplo de clases implementadas. List
Las interfases List, Set y SortedSet son descendientes de la interfase Collection
El concepto de Polimorfismo aplica para todas las clases que implementan estas interfases.
Las clases que implementan la interfase List son: ArrayList y LinkedList
Las clases que implementan la interfase Set son: HashSet y LinkedHashSet
La clase que implementa la sub-interfase SortedSet es: TreeSet.

3.1. Definiendo una clase
Para manipular las colecciones usaremos la clase Producto compuesta por dos atributos, un constructor y un método get.

Producto.java
public class Producto {

private String nombre;
private int cantidad;
public Producto(String s, int i) {
nombre = s;
cantidad = i;
}

public String toString(){
return ("Nombre: "+nombre+" Cantidad: "+cantidad);
}

public String getNombre() {
return this.nombre;
}
}


3.2. Mostrar los elementos de una colección. ArrayList

En el ejemplo crearemos una lista del mercado y mostraremos sus elementos.
- Primero se importan las librerías de java.util.* donde se concentran la gran mayoría de las Clases del "Collection Framework".
- Se inicia la declaración de la clase seguido de su método principal main.
- Se definen 5 instancias con el constructor de la clase Producto.
- Agregamos estas instancias al ArrayList con el método add
- Mostramos el número de objetos de la colección mediante el método size.
- Se declara una instancia Iterator la cual facilita la extracción de objetos de la colección.
- Se extrae los objetos del ArrayList y se muestran en pantalla.
- Se elimina el objeto con indice 2. Se muestra la lista nuevamente.
- Se eliminan todos los objetos mediante el método clear.

import java.util.*;
public class MercadoLista
{
public static void main(String args[])
{
// Definir 5 instancias de la Clase Producto
Producto pan = new Producto("Pan", 6);
Producto leche = new Producto("Leche", 2);
Producto manzanas = new Producto("Manzanas", 5);
Producto brocoli = new Producto("Brocoli", 2);
Producto carne = new Producto("Carne", 2);

// Definir un ArrayList
ArrayList lista = new ArrayList();

// Colocar Instancias de Producto en ArrayList
lista.add(pan);
lista.add(leche);
lista.add(manzanas);
lista.add(brocoli);
// Las listas inician en 0 (Cero)
// Indica el indice de insercion
lista.add(1, carne);
lista.add(carne);

// Imprimir contenido de ArrayLists
System.out.println(" Lista del mercado con " + lista.size() +
" productos");

// Definir Iterator para extraer e imprimir sus valores

Iterator it = lista.iterator();
while ( it.hasNext() ) {
Object objeto = it.next();
Producto producto = (Producto)objeto;
System.out.println(producto);
}

// Eliminar elemento de ArrayList
lista.remove(2);
System.out.println(" Lista del mercado con " + lista.size() +
" productos");
// Definir Iterator para extraer e imprimir valores

Iterator it2 = lista.iterator();
while ( it2.hasNext() ) {
Producto producto = (Producto)it2.next();
System.out.println(producto);
}

// Eliminar todos los valores del ArrayList
lista.clear();
System.out.println(" Lista del mercado con " + lista.size() +
" productos");
}
}



3.3. Evitar objetos duplicados. HashSet
- Primero modificamos la clase Producto agregando dos métodos equals y hashCode
- El método equals desarrolla como se comparan dos objetos
- El método hashCode devuelve un identificador único.

Producto.java
public class Producto {

private String nombre;
private int cantidad;

public Producto(String s, int i) {
nombre = s;
cantidad = i;
}

public String toString(){
return ("Nombre: "+nombre+" Cantidad: "+cantidad);
}

public String getNombre() {
return this.nombre;
}

public boolean equals( Object objeto ) {
if (objeto == null) return false;

Producto producto = (Producto)objeto;
if (this.getNombre().equals(producto.getNombre()) )
return true;

return false;
}

public int hashCode() {
return this.getNombre().hashCode();
}

}

- Aun cuando se agregaron 6 elementos, la lista solo cuenta con 5. Set no permite duplicados.
- La evaluacion de duplicidad de objetos se realiza mediante los métodos equals y hashCode.
- Un Set no cuenta con indice, por lo que para eliminar un elemento se indica el objeto.

MercadoHashSet.java
import java.util.*;
public class MercadoHashSet
{
public static void main(String args[])
{
// Definir 5 instancias de la Clase Producto
Producto pan = new Producto("Pan", 6);
Producto leche = new Producto("Leche", 2);
Producto manzanas = new Producto("Manzanas", 5);
Producto brocoli = new Producto("Brocoli", 2);
Producto carne = new Producto("Carne", 2);
Producto res = new Producto("Carne", 3);

// Definir un HashSet
HashSet lista = new HashSet();
lista.add(pan);
lista.add(leche);
lista.add(manzanas);
lista.add(brocoli);
lista.add(carne);
lista.add(res);

// Imprimir contenido de HashSet
// Aunque son insertados 6 elementos, el HashSet solo contiene 5
// Se debe a que un Set no permite elementos duplicados.

System.out.println(" Lista del mercado con " + lista.size() +
" productos");

// Definir Iterator para extraer e imprimir valores

for( Iterator it = lista.iterator(); it.hasNext(); ) {
Object objeto = it.next();
Producto producto = (Producto)objeto;
System.out.println(producto);
}

// No es posible eliminar elementos por indice
// En un HashSet solo se elimina por valor de Objeto

lista.remove(manzanas);
System.out.println(" Lista del mercado con " + lista.size() +
" productos");
for( Iterator it2 = lista.iterator(); it2.hasNext();) {
Producto producto = (Producto)it2.next();
System.out.println(producto);
}

// Eliminar todos los valores del ArrayList
lista.clear();
System.out.println(" Lista del mercado con " + lista.size() +
" productos");
}
}


3.4. Manejar colecciones ordenadas. TreeSet
- Primero modificamos la clase Producto implementando un comparador para el ordenamiento.
- La clase implementa Comparable
- El método compareTo de la interfase Comparable indica que atributos se usaran para comparar.

import java.util.*;
public class Producto implements Comparable {

private String nombre;
private int cantidad;

public Producto(String s, int i) {
nombre = s;
cantidad = i;
}

public String toString(){
return ("Nombre: "+nombre+" Cantidad: "+cantidad);
}

public String getNombre() {
return this.nombre;
}

public boolean equals( Object objeto ) {
// Indica en base a que atributos se iguala el objeto
if (objeto == null) return false;
Producto producto = (Producto)objeto;
if (this.getNombre().equals(producto.getNombre()) ) return true;

return false;
}

public int hashCode() {
// retorna un identificador unico del objeto.
return this.getNombre().hashCode();
}

public int compareTo( Object objeto ) {
// Indica en base a que atributos se compara el objeto
// Devuelve +1 si this es > que objeto
// Devuelve -1 si this es < que objeto
// Devuelve 0 si son iguales

Producto producto = (Producto)objeto;
String nombreObjeto = producto.getNombre().toLowerCase();
String nombreThis = this.getNombre().toLowerCase();

return( nombreThis.compareTo( nombreObjeto ) );
}
}

- Un TreeSet no permite elementos duplicados.
- Un TreeSet mantiene la lista ordenada.
- El elemento a comparar debe contar con métodos equals, hashCode y compareTo.

MercadoTreeSet.java
import java.util.*;
public class MercadoTreeSet
{
public static void main(String args[])
{
// Definir 5 instancias de la Clase Producto
Producto pan = new Producto("Pan", 6);
Producto leche = new Producto("Leche", 2);
Producto manzanas = new Producto("Manzanas", 5);
Producto brocoli = new Producto("Brocoli", 2);
Producto carne = new Producto("Carne", 2);
Producto res = new Producto("Carne", 3);

// Definir un TreeSet
TreeSet lista = new TreeSet();
lista.add(pan);
lista.add(leche);
lista.add(manzanas);
lista.add(brocoli);
lista.add(carne);
lista.add(res);

// Imprimir contenido de TreeSet
// Aunque se agregan 6 elementos, el TreeSet solo contiene 5
// TreeSet no permite elementos duplicados,
// TreeSet detecta que el elemento "Carne" esta duplicado
// Notese que el orden del TreeSet refleja un orden ascendente
mostrarLista(lista);

// No es posible eliminar elementos por indice
// Un TreeSet solo elimina por valor de Objeto
lista.remove(manzanas);
mostrarLista(lista);

// Eliminar todos los valores del TreeSet
lista.clear();
mostrarLista(lista);
}

public static void mostrarLista(Collection lista) {
System.out.println(" Lista del mercado con " + lista.size() +
" productos");
for( Iterator it = lista.iterator(); it.hasNext();) {
Producto producto = (Producto)it.next();
System.out.println(producto);
}
}
}


3.5. Ordenar y buscar en Colecciones. Collections.
- La clase Collections (que no es la interface Collection) nos permite ordenar y buscar elementos en listas.
- Se usaran los métodos sort y binarySearch
- Los objetos de la lista deben tener métodos equals, hashCode y compareTo adecuados.

MercadoCollections.java
import java.util.*;
public class MercadoCollections
{
public static void main(String args[])
{
// Definir 5 instancias de la Clase Producto
Producto pan = new Producto("Pan", 6);
Producto leche = new Producto("Leche", 2);
Producto manzanas = new Producto("Manzanas", 5);
Producto brocoli = new Producto("Brocoli", 2);
Producto carne = new Producto("Carne", 2);

// Definir un ArrayList
ArrayList lista = new ArrayList();

// Colocar Instancias de Producto en ArrayList
lista.add(pan);
lista.add(leche);
lista.add(manzanas);
lista.add(brocoli);
lista.add(1,carne);

// Imprimir contenido de ArrayList
mostrarLista(lista);

// Ordenar elemntos de ArrayList
Collections.sort(lista);

// Imprimir contenido de ArrayList
mostrarLista(lista);

// Buscar un elemento que se compare con Pan de tipo String
String buscar = "Pan";
int indice = Collections.binarySearch(lista,buscar);

System.out.println(buscar+" es el elemento "+indice);

}

public static void mostrarLista(Collection lista) {
System.out.println(" Lista del mercado con " + lista.size() +
" productos");
int i=0;
for( Iterator it = lista.iterator(); it.hasNext(); i++) {
Producto producto = (Producto)it.next();
System.out.println(i+"-"+producto);
}
}
}


Producto.java
import java.util.*;
public class Producto implements Comparable {

private String nombre;
private int cantidad;

public Producto(String s, int i) {
nombre = s;
cantidad = i;
}

public String toString(){
return ("Nombre: "+nombre+" Cantidad: "+cantidad);
}

public String getNombre() {
return this.nombre;
}

public boolean equals( Object objeto ) {
// Indica en base a que atributos se iguala el objeto
if (objeto == null) return false;
Producto producto = (Producto)objeto;
if (this.getNombre() == producto.getNombre() ) return true;

return false;
}

public int hashCode() {
// retorna un identificador unico del objeto.
return this.getNombre().hashCode();
}

public int compareTo( Object objeto ) {
// Indica en base a que atributos se compara el objeto
// Devuelve +1 si this es > que objeto
// Devuelve -1 si this es < que objeto
// Devuelve 0 si son iguales

// Dependera del argumento como comparar los atributos.
String nombreObjeto;
if (objeto instanceof Producto ) {
Producto producto = (Producto)objeto;
nombreObjeto = producto.getNombre().toLowerCase();
}
else
if (objeto instanceof String) {
String producto = (String)objeto;
nombreObjeto = producto.toLowerCase();
}
else {
nombreObjeto = "";
}

String nombreThis = this.getNombre().toLowerCase();

return( nombreThis.compareTo( nombreObjeto ) );
}
}

4. Ejemplo de clases implementadas. Map

La clase que implementan la interfase Map es HashMap.
La clase que implementa la sub-interfase SortedMap es TreeMap.

4.1. Ejemplo de HashMap
- Se define una instancia de la clase HashMap
- Se colocan 9 pares clave-valor con el método put.
- Se muestra el contenido mediante un iterador que extrae los valores del HashMap.
- Se define un arreglo de String con tres claves para eliminar de la agenda.
- Se elimina las claves de la agenda
- el método keySet de la clase HashMap devuelve un conjunto (un objeto Set) que contiene las llaves del mapa, el cual se puede iterar.

Ejercicio: Verifique si permite duplicados

AgendaHashMap.java
import java.util.*;
public class AgendaHashMap
{
public static void main(String args[])
{
// Definir un HashMap
HashMap agenda = new HashMap();

// Agregar pares "clave"-"valor" al HashMap
agenda.put("Doctor", "(+52)-4000-5000");
agenda.put("Casa", "(888)-4500-3400");
agenda.put("Hermano", "(575)-2042-3233");
agenda.put("Tio", "(421)-1010-0020");
agenda.put("Suegros", "(334)-6105-4334");
agenda.put("Oficina", "(304)-5205-8454");
agenda.put("Abogado", "(756)-1205-3454");
agenda.put("Papa", "(55)-9555-3270");
agenda.put("Tienda", "(874)-2400-8600");

// Definir Iterator para extraer/imprimir valores
mostrarMapa(agenda);

// Definir un arreglo con valores determinados
String personas[] = {"Tio", "Suegros", "Abogado"};

// Eliminar los valores contenidos en el arreglo
for(int i = 0; i < personas.length; i++) {
agenda.remove(personas[i]);
}
mostrarMapa(agenda);
}

public static void mostrarMapa(Map agenda) {
System.out.println(" Agenda con " + agenda.size() +
" telefonos");
for( Iterator it = agenda.keySet().iterator(); it.hasNext();) {
String clave = (String)it.next();
String valor = (String)agenda.get(clave);
System.out.println(clave + " : " + valor);
}
}
}

4.2. Ejemplo de TreeMap
- En un TreeMap los elementos estan ordenados por la clave
- Luego se definen dos referencias de la interfase SortedMap
- En la primera se colocan las claves que se encuentran entre A y O. Metodo submap("A", "O")
- La segunda almacena las claves desde la P hacia el final.
- Estas comparaciones se han hecho con la clase String.
- Otras clases deberán definir sus propios métodos compareTo, equals y hashCode.

AgendaTreeMap.java
import java.util.*;
public class AgendaTreeMap
{
public static void main(String args[])
{
// Definir un TreeMap
TreeMap agenda = new TreeMap();

// Agregar pares "clave"-"valor" al HashMap
agenda.put("Doctor", "(+52)-4000-5000");
agenda.put("Casa", "(888)-4500-3400");
agenda.put("Hermano", "(575)-2042-3233");
agenda.put("Tio", "(421)-1010-0020");
agenda.put("Suegros", "(334)-6105-4334");
agenda.put("Oficina", "(304)-5205-8454");
agenda.put("Abogado", "(756)-1205-3454");
agenda.put("Papa", "(55)-9555-3270");
agenda.put("Tienda", "(874)-2400-8600");

// Notese que el orden del TreeMap refleja un orden ascendente
// en sus elementos independientemente del orden de insercion.
// Debido al uso de String se refleja un orden alfabetico
mostrarMapa(agenda);

// Definir dos TreeMap nuevos
SortedMap agendaAO = agenda.subMap("A", "O");
SortedMap agendaPZ = agenda.tailMap("P");

System.out.println("---- Agenda A-O ----");
mostrarMapa(agendaAO);

System.out.println("---- Agenda P-Z ----");
mostrarMapa(agendaPZ);
}

public static void mostrarMapa(Map agenda) {
System.out.println(" Agenda con " + agenda.size() +
" telefonos");
for( Iterator it = agenda.keySet().iterator(); it.hasNext();) {
String clave = (String)it.next();
String valor = (String)agenda.get(clave);
System.out.println(clave + " : " + valor);
}
}
}

5. Colecciones desde java 1.5

A partir de la version 5 de java se presentan tres mejoras en el manejo de colecciones.
Genericos: Al momento de compilar se agrega la clase de la cual esta compuesta la coleccion, de tal manera que no se requiere cast para leer una coleccion que almacena elementos del mismo tipo.

Loop optimizado: Eliminando la necesidad de crear iteradores. Tambien se aplica a primitivas.

Autoboxing: Automaticamente se comvierten primitivas a objetos (int <---> Integer) tanto al almacenar como al leerlas de la coleccion.

Producto.java
public class Producto {

private String nombre;
private int cantidad;

public Producto(String s, int i) {
nombre = s;
cantidad = i;
}

public String toString(){
return ("Nombre: "+nombre+" Cantidad: "+cantidad);
}

public String getNombre() {
return this.nombre;
}
}


MercadoLista.java
import java.util.*;

public class MercadoLista
{
public static void main(String args[])
{
// Definir 5 instancias de la Clase Producto
Producto pan = new Producto("Pan", 6);
Producto leche = new Producto("Leche", 2);
Producto manzanas = new Producto("Manzanas", 5);
Producto brocoli = new Producto("Brocoli", 2);
Producto carne = new Producto("Carne", 2);

// Definir un ArrayList de Productos
ArrayList<Producto> lista = new ArrayList<Producto>();

// Colocar Instancias de Producto en ArrayList
lista.add(pan);
lista.add(leche);
lista.add(manzanas);
lista.add(brocoli);

// Las listas inician en 0 (Cero)
// Indica el indice de insercion
lista.add(1, carne);
lista.add(carne);

// Imprimir contenido de ArrayLists
System.out.println(" Lista del mercado con " + lista.size() +
" productos");

// Utilizar el for optimizado para recorrer la lista.
for ( Producto producto : lista ) {
System.out.println(producto);
}

// Eliminar elemento de ArrayList
lista.remove(2);
System.out.println(" Lista del mercado con " + lista.size() +
" productos");

// Utilizar el for optimizado para recorrer la lista.
for ( Producto producto2 : lista ) {
System.out.println(producto2);
}

// Eliminar todos los valores del ArrayList
lista.clear();
System.out.println(" Lista del mercado con " + lista.size() +
" productos");

// Nueva forma de utilizar el for para primitivas
int[] array = {1,2,4,8,16,32,64};
for (int i : array) {
System.out.println(i);
}
}
}


AgendaHashMap.java
import java.util.*;
public class AgendaHashMap
{
public static void main(String args[])
{
// Definir un HashMap
HashMap<String,String> agenda = new HashMap<String,String>();

// Agregar pares "clave"-"valor" al HashMap
agenda.put("Doctor", "(+52)-4000-5000");
agenda.put("Casa", "(888)-4500-3400");
agenda.put("Hermano", "(575)-2042-3233");
agenda.put("Tio", "(421)-1010-0020");
agenda.put("Suegros", "(334)-6105-4334");
agenda.put("Oficina", "(304)-5205-8454");
agenda.put("Abogado", "(756)-1205-3454");
agenda.put("Papa", "(55)-9555-3270");
agenda.put("Tienda", "(874)-2400-8600");

// Un nuevo loop para extraer/imprimir valores
for(String s : agenda.keySet()) {
System.out.println(s);
}
for(String s : agenda.values()) {
System.out.println(s);
}

// Definir un arreglo con valores determinados
String personas[] = {"Tio", "Suegros", "Abogado"};

// Eliminar los valores contenidos en el arreglo
for(String persona : personas) {
agenda.remove(persona);
}

// Mostrar la agenda
for (Map.Entry<String,String> telefono : agenda.entrySet()) {
System.out.println(telefono.getKey()+" = "+telefono.getValue());
}
}
}


6. EJERCICIO
public class Pelicula6 {
private int codigo;
private String titulo;
private float precio;
private String tipo;
Pelicula(int codigo, String titulo, float precio, String tipo) {
...
}
...
}
public class TestCartelera {
public static void main (String[] args) {
...
}
}

En la clase pelicula agregue los métodos compareTo, equals y hashCode.
En el programa TestCartelera.java cree una lista ordenada (TreeSet) de 5 películas y muestrelas en orden alfabetico. Muestrelas en orden inverso también.
Agregue dos películas mas y muestre las películas.
Coloque las 7 peliculas en una mapa (TreeMap) el objeto pelicula será la clave y su valor será un String que almacena el nombre del cliente que lo alquila.
Revise los métodos de la clase Collections.