Programación OO Anexo: Colecciones Dr. Eric Jeltsch F. Collection << interface >> Collection public void clear(); public boolean add(Object o); public boolean addAll(Collection c); public boolean remove(Object o); public boolean removeAll(Collection c); public boolean contains(Object o); public boolean containsAll(Collection c); public boolean equals(Object o); public boolean isEmpty(); public int size(); public boolean retainAll(Collection c); public Iterator iterator(); publicObject [] toArray(); public Object [] toArray(Object [] a); public int hashCode(); public String toString() Fig.: la Interface Collection << interface >> Iterator public boolean hasNext(); public Object next(); public void remove(); Fig.: La Interface Iterator << interface >> java.util.Comparator public int compare(Object o1, Object o2) // compara 2 Argumentos respecto de su orden public boolean equals(Object arg) // testea, si 2 Objetos, resp. Comparator-Objetos son =. Fig.: La Interface Comparator ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 1 Programación OO Colecciones Dr. Eric Jeltsch F. << interface >> List public public public public public public public public public public public public public public public public public public public public public void add(int index, Object element); boolean add(Object o); boolean addAll(Collection c); boolean addAll(int index, Collection c) void clear(); boolean equals(Object object); boolean contains(Object element); boolean containsAll(Collection collection); Object remove(int index) boolean remove(Object element); boolean removeAll(Collection c); boolean retainAll(Collection c); Object get(); int hashCode(); Iterator iterator(); ListIterator listIterator(): ListIterator listIterator(int startIndex); Object set(int index, Obeject element); List subList(int fromIndex, int toIndex); Object [] toArray(); Object [] toArray(Object [] a); Fig.: La Interface List << interface >> Collection << interface >> List LinkedList << Constructores >> public LinkedList(); public LinkedList(Collection collection); << Metodos >> public void addFirst(Object object); public void addLast(Object object); public Object getFirst(); public Object getLast(); public Object removeFirst(); public Object removeLast(); ArrayList Vector << Constructores >> public ArrayList(); public ArrayList(Collection collection); public ArrayList(int startCapacidad); << Metodos >> protected void removeRange (int fromIndex, int toIndex) // elimina parte de la lista de // fromIndex hasta toIndex. fromIndex // es también borrado, // lo que no ocurre con toIndex. Fig.: LinkedList, ArrayList, Vector ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 2 Programación OO Colecciones Dr. Eric Jeltsch F. << interface >> Collection << interface >> Set public boolean add(Object element); public boolean addAll(Collection collection); public void clear(); public boolean equals(Object object); public boolean contains(Object element); public boolean containsAll(Collection collection); public int hashCode(); public Iterator iterator(); public boolean remove(Object element); public boolean removeAll(Collection collection); public boolean retainAll(Collection collection); public int size(); public Object[] toArray(); public Object[] toArray(Object[] a); HashSet public HashSet(); public HashSet(Collection collection); public HashSet(int startCapacidad); public HashSet(int startCapacidad, float factorCarga); << interface >> SortedSet public Object first(); public Object last(); public SortedSet headSet(Object toElement); public SortedSet subSet(Object fromElement, Object toElement); public SortedSet tailSet(Object fromElement); public Comparator comparator(); TreeSet public TreeSet() public TreeSet(Collection collection); public TreeSet(Comparator vergleich); public TreeSet(SortedSet collection); ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 3 Programación OO Colecciones Dr. Eric Jeltsch F. Interface Map, SortedMap << interface >> Collection << interface >> Map public void clear(); public boolean containsKey(Object key); public boolean containsValue(Object value); public Set entrySet(); public Object get(Object key); public boolean isEmpty(); public Set keySet(); public Object remove(Object key); public int size(); public Collection values(); HashMap public HashMap(); public HashMap(Map collection); public HashMap(int startCapacidad); public HashMap(int startCapacidad, int factorCarga); Hashtable << interface >> SortedMap public Comparator comparator(); public Object firstKey(); public Object lastKey(); public SortedMap headMap(Object toKey); public SortedMap subMap(Object fromKey, Object toKey); public SortedMap tailMap(Object fromKey); TreeMap public TreeMap(); public TreeMap(Map collection); public TreeMap(Comparator vergleich); public TreeMap(SortedMap collection); En la API Collections, es uno de los cambios más notables experimentados por el paquete java.util del JDK1.2, pues las clases e interfaces que la componen ofrecen una estructura independiente de la implementación, con el fin de mejorar y manejar colecciones de objetos. Observar que Java1.1 proporcionaba la interfaz Enumeration y las seis clases siguientes: Vector, Stack, BitSet, Dictionary, Hashtable y Properties. ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 4 Programación OO Colecciones Dr. Eric Jeltsch F. La clase Vector ofrece la posibilidad de implementar un array creciente. El array crece en la medida que se le van ingresando elementos. También se puede reducir el tamaño del array una vez eliminado algunos de ellos, esto último se logra con trimToSize(). La clase Stack ofrece la posibilidad de crear y usar objetos de almacenamiento denominados Pilas. Se almacena información colocándola en una pila y se elimina o recupera información sacándola de la pila. El último objeto colocado en una pila es el primer objeto que se puede recuperar. La clase Stack extiende la clase Vector. Los objetos se disponen en la pila por medio del método push() y se recuperan por el pop(). También posee un método llamado search() que busca un objeto determinado. El método peek() devuelve el elemento de la parte de arriba de la pila. Las clases BitSet se utiliza para crear objetos que mantienen un conjunto de bits. En general se usan en aplicaciones orientadas al sistema operativo o en temas asociados a señales. Las clases Dictionary, Hashtable y Properties, son tres generaciones de clases que implementan la capacidad de proporcionar un almacenamiento y recuperación de datos en base a claves, en este segmento deberían recordarse de las tablas de hashing como ejemplo de lo que son capaces de realizar. Clases e interfaces de la API Collections del JD K 1.2 La API Collections del JDK 1.2 ha añadido 10 nuevas interfaces y 13 nuevas clases. Estas clases e interfaces adicionales ofrecen una API potente a la hora de trabajar con tipos diferentes de colecciones de objetos. Las interfaces de colecciones nuevas que JDK 1.2 ha introducido son: Collection : Define métodos que implementan el concepto de un grupo de objetos, a los que se denomina elementos. La interfaz Collection se corresponde con un “saco” en el cual una colección permite que hallan objetos duplicados. Define un amplio espectro de métodos que sirven para agregar, quitar y recuperar objetos de la colección, además de métodos que operan en la propia colección. List: Amplía la interfaz Collection con el objeto de implementar una colección ordenada de objetos. Dado que las listas están ordenadas, los objetos de la List pueden ser indexados. La interfaz ListIterator ofrece métodos para que se repitan los elementos de una lista. Set: Amplía la interfaz Collection con el objeto de implementar un conjunto finito. Los conjuntos difieren de la lista en que no permiten elementos duplicados. SortedSet: Un Set cuyos elementos están ordenados en orden ascendente. Comparator: Ofrece el método compare() con el fin de comparar los elementos de una colección. Iterator: Proporciona métodos para repetir los elementos de una colección. En el JDK 1.2, la interfaz Iterator sustituye a la interfaz Enumeration. ListIterator: Amplía la interfaz Iterator con el fin de admitir la repetición bidireccional ________________________________________________________________________ 5 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. de listas. Map: Reemplaza a la clase Dictionary como forma de asociar claves con valores. SortedMap: Un Map cuyos elementos están ordenados en orden ascendente. Map. Entry : Una interfaz interna de la interfaz Map que define métodos para trabajar con un par individual de clave-valor. Existiendo otras más como LinkedList, ArrayList, HashSet, TreeSet, HashMap y otras. EJEMPLOS VARIOS: // Demo para ArrayList. import java.util.*; class ArrayListDemo { public static void main(String args[]) { // crea un array list ArrayList al = new ArrayList(); System.out.println("Tamaño inicial del ArrayList: " + al.size()); // agregar elementos al array list al.add("C"); al.add("A"); al.add("E"); al.add("B"); al.add("D"); al.add("F"); al.add(1, "A2"); System.out.println("Tamaño del ArrayList, luego de...: " + al.size()); // display el array list System.out.println("Contenidos en ArrayList: " + al); // Elimina elementos del array list al.remove("F"); al.remove(2); System.out.println("Tamaño del ArrayList luego de borrar: " + al.size()); System.out.println("Contenido del ArrayList: " + al); } } ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 6 Programación OO Colecciones Dr. Eric Jeltsch F. // Convertir un ArrayList en un array. import java.util.*; class ArrayList_Array { public static void main(String args[]) { // Crea un array list ArrayList al = new ArrayList(); // Agrega elementos al array list al.add(new Integer(1)); al.add(new Integer(2)); al.add(new Integer(3)); al.add(new Integer(4)); System.out.println("Contenido del ArrayList: " + al); // obtener el array Object ia[] = al.toArray(); int sum = 0; // suma el array for(int i=0; i<ia.length; i++) sum += ((Integer) ia[i]).intValue(); System.out.println("La suma es: " + sum); } } // Demo para LinkedList. import java.util.*; class LinkedListDemo { public static void main(String args[]) { // crea una linked list LinkedList ll = new LinkedList(); // agrega elementos a la linked list ll.add("F"); ll.add("B"); ll.add("D"); ll.add("E"); ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 7 Programación OO Colecciones Dr. Eric Jeltsch F. ll.add("C"); ll.addLast("Z"); ll.addFirst("A"); ll.add(1, "A2"); System.out.println("Contenido original de ll: " + ll); // elimina elementos de la linked list ll.remove("F"); ll.remove(2); System.out.println("Contenido de la ll después de borrar: " + ll); // elimina los elementos primero y ultimo ll.removeFirst(); ll.removeLast(); System.out.println("ll despues de eliminar primero y ultimo: " + ll); // obtener y setear un valor Object val = ll.get(2); ll.set(2, (String) val + " cambio"); System.out.println("ll despues de cambio: " + ll); } } // Usando comparator para ordenar cuentas por apellido. import java.util.*; // Compara los string de los nombre. class TComp implements Comparator { public int compare(Object a, Object b) { int i, j, k; String aStr, bStr; aStr = (String) a; bStr = (String) b; // hallar el indice del apellido i = aStr.lastIndexOf(' '); j = bStr.lastIndexOf(' '); k = aStr.substring(i).compareTo(bStr.substring(j)); if(k==0) // apellido match, chequea el nombre entero return aStr.compareTo(bStr); ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 8 Programación OO Colecciones Dr. Eric Jeltsch F. else return k; } } class TreeMapDemo2 { public static void main(String args[]) { // Crea un tree map TreeMap tm = new TreeMap(new TComp()); // elementos al map tm.put("Juan Perez", new Double(3434.34)); tm.put("Tomas Contreras", new Double(123.22)); tm.put("Juan Palacios", new Double(1378.00)); tm.put("Teodoro Rosas", new Double(99.22)); tm.put("Rafael Sepulveda", new Double(-19.08)); // seteando la entrada Set set = tm.entrySet(); // iterator Iterator itr = set.iterator(); // Display los elementos while(itr.hasNext()) { Map.Entry me = (Map.Entry)itr.next(); System.out.print(me.getKey() + ": "); System.out.println(me.getValue()); } System.out.println(); // Depositamos 1000 en la cuenta de Juan Perez double balance = ((Double)tm.get("Juan Perez")).doubleValue(); tm.put("Juan Perez", new Double(balance + 1000)); System.out.println("Nuevo balance de Juan Perez : " + tm.get("Juan Perez")); } } // Demo para ciertos algoritmos. import java.util.*; class AlgoritmosDemo { public static void main(String args[]) { ________________________________________________________________________ Ingeniería en Computación, Universidad de La Serena 9 Programación OO Colecciones Dr. Eric Jeltsch F. // Crea e inicializa una linked list LinkedList ll = new LinkedList(); ll.add(new Integer(-8)); ll.add(new Integer(20)); ll.add(new Integer(-20)); ll.add(new Integer(8)); // Crea un comparador en orden inverso Comparator r = Collections.reverseOrder(); // ordena la lista usando el comparador Collections.sort(ll, r); // obtener el iterator Iterator li = ll.iterator(); System.out.print("Lista ordenada: "); while(li.hasNext()) System.out.print(li.next() + " "); System.out.println(); Collections.shuffle(ll); // display lista random li = ll.iterator(); System.out.print("Lista barajada: "); while(li.hasNext()) System.out.print(li.next() + " "); System.out.println(); System.out.println("Minimum: " + Collections.min(ll)); System.out.println("Maximum: " + Collections.max(ll)); } } // Demo para varias operaciones con Vector. import java.util.*; class VectorDemo { public static void main(String args[]) { // tamaño inicial es 3, incrementando en 1 Vector v = new Vector(3, 1); System.out.println("Tamaño Inicial: " + v.size()); System.out.println("Capacidad Inicial: " + v.capacity()); ________________________________________________________________________ 10 Ingeniería en Computación, Universidad de La Serena Programación OO v.addElement(new v.addElement(new v.addElement(new v.addElement(new Colecciones Dr. Eric Jeltsch F. Integer(1)); Integer(2)); Integer(3)); Integer(4)); System.out.println("Capacidad luego de 4 adiciones: " + v.capacity()); v.addElement(new Double(5.45)); System.out.println("Capacidad actual: " + v.capacity()); v.addElement(new Double(6.08)); v.addElement(new Integer(7)); System.out.println("capacidad Actual: " + v.capacity()); v.addElement(new Float(9.4)); v.addElement(new Integer(10)); System.out.println("Capacidad Actual: " + v.capacity()); v.addElement(new Integer(11)); v.addElement(new Integer(12)); System.out.println("Primer elemento: " + (Integer)v.firstElement()); System.out.println("Ultimo elemento: " + (Integer)v.lastElement()); if(v.contains(new Integer(5)))// pregunte por 3!! System.out.println("Vector contiene 5."); // enumera los elementos en el vector. Enumeration vEnum = v.elements(); System.out.println("\nElementos en vector:"); while(vEnum.hasMoreElements()) System.out.print(vEnum.nextElement() + " "); System.out.println(); } } // Demo para la clase Stack. ________________________________________________________________________ 11 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. import java.util.*; class StackDemo { static void showpush(Stack st, int a) { st.push(new Integer(a)); System.out.println("push(" + a + ")"); System.out.println("stack: " + st); } static void showpop(Stack st) { System.out.print("pop -> "); Integer a = (Integer) st.pop(); System.out.println(a); System.out.println("stack: " + st); } public static void main(String args[]) { Stack st = new Stack(); System.out.println("stack: " + st); showpush(st, 42); showpush(st, 66); showpush(st, 99); showpop(st); showpop(st); showpop(st); try { showpop(st); } catch (EmptyStackException e) { System.out.println("stack vacio."); } } } La clase Properties es una subclase de Hashtable que se utiliza para mantener listas de valores en las que la claves una cadena y el valor es también un objeto String. /* Una guía telefonica en la cual se ingresan los numeros con sus respectivos nombres. En la eventualidad que se le solicitara el numero correspondiente a un cliente, ________________________________________________________________________ 12 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. bastara con ingresar el nombre y le saldra el numero. */ import java.io.*; import java.util.*; class LibroFonos { public static void main(String args[]) throws IOException { Properties ht = new Properties(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String nombre, numero; FileInputStream fin = null; boolean cambio = false; // atrapando el archivo fono.dat. try { fin = new FileInputStream("fono.dat"); } catch(FileNotFoundException e) { // ignorando archivos que no corresponden } /* si el archivo ya existe, ingresa los numeros telef. existentes. */ try { if(fin != null) { ht.load(fin); fin.close(); } } catch(IOException e) { System.out.println("Error al leer archivo."); } // usuario ingresa nuevos nombres y numeros. do { System.out.println("Ingrese nuevo Nombre" + " ('quit' para Stop): "); nombre = br.readLine(); if(nombre.equals("quit")) continue; System.out.println("Ingrese Numero: "); numero = br.readLine(); ht.put(nombre, numero); cambio = true; } while(!nombre.equals("quit")); // Si el archivo tiene cambios, salvarlos. if(cambio) { FileOutputStream fono = new FileOutputStream("fono.dat"); ht.store(fono, "Guia Telefonica"); fono.close(); } // Miremos el numero dado el nombre. ________________________________________________________________________ 13 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. do { System.out.println("Ingrese nombre a encontrar" + " ('quit' to quit): "); nombre = br.readLine(); if(nombre.equals("quit")) continue; numero = (String) ht.get(nombre); System.out.println(numero); } while(!nombre.equals("quit")); } } Un Set es un conjunto, en el cual no pueden aparecer elementos repetidos. Set tiene los mismos métodos como Collection. Standard-Implementación para Set son los HashSet (Array y los TreeSet (Arboles Binarios). import java.util.*; public class SetDemo { public static void main(String args []) { Set set = new HashSet(); set.add("Gerardo"); set.add("Tomas"); ________________________________________________________________________ 14 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. set.add("Michael"); set.add("Pedro"); set.add("Christian"); set.add("Valentina"); System.out.println(set); Set sortedSet = new TreeSet(set); System.out.println(sortedSet); } } Algoritmos La elección de una estructura de datos apropiada es una primera tarea, en la siguiente la biblioteca Java ayuda con su batería de algoritmos estándar. public static void shuffle(List list) // desordena los elementos de una Lista Ejemplo: import java.util.*; public class VectorShuffle { public static void main(String args[]) { Vector v = new Vector(); for (int i = 0; i < 10; i++) v.add(new Integer(i)); Collections.shuffle(v); System.out.println(v); } } public static void shuffle(List list, Random rnd) // desordena los valores de List y usa el Random Generator rnd. public static void reverse(List l) // invierte el orden de los elementos de una lista ________________________________________________________________________ 15 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Los métodos min() y max() buscan el minimo y maximo Elemento en una Collection. El costo es lineal sobre la Collection. Los métodos no hacen distinción si la Lista esta o no ordenada. public static Object min(Collection c) public static Object max(Collection c) public static Object min(Collection c, Comparator vergl) public static Object max(Collection c, Comparator vergl) La clase Collection ofrece 2 métodos sort(), es decir, los elementos de una lista ordenados “estable”. El método sort() ordena los Elementos en su orden natural. Por ejemplo. - según su orden natural (13 < 40) - string , según su orden alfanumérico. (Jorge < Roberto < Ulises) public static void sort(List lista) // ordena la Lista public static void sort(List lista, Comparator c) // ordena la lista con el Comparator c La función ordenar trabaja sólo con objetos List. „sort()“ existe también en la clase Arrays. Ejemplo: El siguiente programa ordena una lista de strings. Se uso el método Arrays.asList() para la construcción de una Lista desde un Array. import java.util.*; public class CollectionsSortDemo { public static void main(String args[]) { String feld[] = { "Regina","Angela","Michaela","Maria","Josefa", "Amalia","Vera","Valentina","Daniela","Saida", "Linda","Elisa" }; List l = Arrays.asList(feld); Collections.sort(l); System.out.println(l); } } ________________________________________________________________________ 16 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Ejemplo: El siguiente programa ordena una lista de Doubles. import java.util.*; public class CollectionsReverseSortDemo { public static void main(String args[]) { Vector v = new Vector(); for (int i = 0; i < 10; i++) { v.add(new Double(Math.random())); } Comparator comparator = Collections.reverseOrder(); Collections.sort(v,comparator); System.out.println(v); } } public static int binarySearch(List lista, Object key) // busca un elemento en la List Lista. Devuelve la posición o un valor menor que 0. En el caso // que key no esté en la Lista. public static int binarySearch(List liste, Object key, Comparator c) // busca un Elemento con la ayuda de Comparator Objetos en la List. Devuelve la posición o //un valor menor que 0, en caso que key no esté en la lista. En particular, List es una Collection ordenada que puede contener elementos duplicados. A menudo List es llamada secuencia, el primer elemento indiciado es cero. List proporciona métodos para manipular elementos usando sus índices, manipulando un rango específico de elementos, buscando algún elemento y manejando un ListIterator para accesar los elementos. La interface List amplia la interfaz Collection a una lista ordenada de objetos, es una de un número de interfaces que representan una colección de datos, conocidos con el nombre de Collection, esta en particular define métodos para trabajar con colecciones arbitrarias de objetos. La interface List es implementada por clases ArrayList(es la implementación de un array resizable de una List), LinkedList(es la implementación de una lista enlazada de una List) y Vector(proporciona la capacidad a la estructura de array de resize dinamicamente.). La aplicación siguiente usa ArrayList para mostrar las capacidades de la interface Collection. Aplicación(CollectionDemo) // Usando la interface Collection import java.util.*; import java.awt.Color; ________________________________________________________________________ 17 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. public class CollectionDemo { private String colores[] = { "rojo", "blanco", "azul", "amarillo" }; public CollectionDemo() {/* crea una referencia a aList, como instancia de ArrayList*/ ArrayList aList = new ArrayList(); aList.add( Color.magenta );// agrega un objeto a colores for ( int k = 0; k < colores.length; k++ ) aList.add( colores[ k ] ); aList.add( Color.cyan ); // agrega otro color /* para desplegar todos los elementos de aList, donde get es llamado para recuperar los valores de los elementos individuales, y size es llamado para obtener el número de elementos en ArrayList*/ System.out.println( "\nArrayList: " ); for ( int k = 0; k < aList.size(); k++ ) System.out.print( aList.get( k ) + " " ); /* llamada al método eliminar pasando aList como argumento, este método elimina los String desde Collection*/ eliminarStrings( aList ); System.out.println( "\n\nArrayList despues eliminarStrings: " ); for ( int k = 0; k < aList.size(); k++ ) System.out.print( aList.get( k ) + " " ); } de llamar a public void eliminarStrings( Collection c ) { /* este método declara un parametro de referencia Collection. Todo elemento Collection es accesado usando un Iterator*/ Iterator i = c.iterator(); // extraer iterator while ( i.hasNext() ) // while collection tiene items /* esta condición testea si el siguiente elemento Object es un String usando el objeto de comparación instanceof. Si el Object es un String, el método Iterator eliminarString es llamadopara eliminar el String desde la Collection*/ if ( i.next() instanceof String ) i.remove(); // elimina objeto String } public static void main( String args[] ) { new CollectionDemo(); } } El resultado es: ArrayList: ________________________________________________________________________ 18 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Java.awt.Color[r=255, g=0, b=255] rojo blanco azul amarillo java.awt.Color[r=255, g=0, b=255] ArrayList despues de llamar a eliminarString: Java.awt.Color[r=255, g=0, b=255] java.awt.Color[r=255, g=0, b=255] La siguiente aplicación es una demo para las Listas Enlazadas, esta aplicación crea 2 LinkedList que contienen String. Los elementos de una List son agregados a la otra. Todos los elementos son convertidos a mayúsculas antes de borrar el rango de los elementos. Aplicación (ListDemo) // Usando Lista enlazada import java.util.*; public class ListDemo { private String colores[] = { "negro", "amarillo", "verde", "azul", "violeta", "plata" }; private String colores2[] = { "oro", "blanco", "cafe", "azul", "gray", "plata" }; public ListDemo() { //declaracion de LinkedList LinkedList link = new LinkedList(); LinkedList link2 = new LinkedList(); /* este ciclo llama a add para accesar los elementos desde los array colores y colores2 al final de link y link2*/ for ( int k = 0; k < colores.length; k++ ) { link.add( colores[ k ] ); link2.add( colores2[ k ] ); } /* addAll accesa todos los elementos de link2 elementos accesados son elementos link2’s*/ al final link.addAll( link2 ); // concatena las lista link2 = null; // libera recursos /* llama al método printList() 3 vecespara imprimir la List imprentaString() para convertir los elementos de String a finalmente eliminar los elementos*/ de link. Los mayuscula y printList( link ); imprentaStrings( link ); printList( link ); System.out.print( "\nEliminando elementos 4 a 6..." ); eliminarItems( link, 4, 7 ); printList( link ); } public void printList( List listRef ) { System.out.println( "\nlist: " ); for ( int k = 0; k < listRef.size(); k++ ) System.out.print( listRef.get( k ) + " " ); System.out.println(); ________________________________________________________________________ 19 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. } public void imprentaStrings( List listRef2 ) { ListIterator listIt = listRef2.listIterator(); while ( listIt.hasNext() ) { Object o = listIt.next(); // extrae item if ( o instanceof String ) // cheque para String listIt.set( ( ( String ) o ).toUpperCase() ); } } public void eliminarItems( List listRef3, int empezar, int terminar ) { listRef3.subList( empezar, terminar ).clear(); // elimina los items } public static void main( String args[] ) { new ListDemo(); } } La ejecución se visualiza así: List: Negro amarillo verde azul violeta plata oro blanco café azul gray plata List: NEGRO AMARILLO VERDE AZUL VIOLETA PLATA ORO BLANCO CAFÉ AZUL GRAY PLATA Eliminando elementos 4 a 6.... NEGRO AMARILLO VERDE AZUL BLANCO CAFÉ AZUL GRAY PLATA Las Collection proporcionan un marco de trabajo de alto rendimiento para manipular algoritmos con una colección de elementos. Tal es el caso de algoritmos para Ordenar, Invertir, búsqueda binaria sobre List. Algoritmos min y max operados sobre Collections. En la siguiente aplicación veremos el algoritmo de ordenar los elementos de una List, en forma ascendente y descendente. Aplicación (ordenar ascendente) // Usando algoritmos de ordenamiento import java.util.*; public class ordenar { private static String colores[] = { "Amarillo", "Dorado", "Cafe", "Gray", "Rojo", "Verde" }; public void printElementos() { ArrayList miList = new ArrayList( Arrays.asList( colores ) ); ________________________________________________________________________ 20 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. System.out.println( "Elementos del array desordenados:\n" + miList ); Collections.sort( miList ); /* usa el algoritmo sort para ordenar los elementos de un ArrayList en orden ascendente */ System.out.println( "Elementos del array ordenados:\n" + miList ); } public static void main( String args[] ) { new ordenar().printElementos(); } } Esta es la salida: Elementos del array desordenados: [Amarillo, Dorado, Café, Gray, Rojo, Verde] Elementos del array ordenados: [Amarillo, Café, Dorado, Gray, Rojo, Verde] Aplicación (ordenar descendente) /* Usando un objeto Comparator con el algoritmo de ordenamiento*/ import java.util.*; public class ordenar1 { private static String colores[] = { "Amarillo", "Dorado", "Cafe", "Gray", "Rojo", "Verde" }; public void printElementos() { List laList = Arrays.asList( colores );// extraer la List System.out.println( "Elementos del Array desordenados:\n" + laList ); /* ordenar los elementos en orden descendente, reverseOrder() devuelve un objeto Comparator que representa la Collection en orden inverso, notar que esta considerado el orden lexicografico*/ Collections.sort( laList, Collections.reverseOrder() ); System.out.println("Elementosrdenados:\n" + laList ); } public static void main( String args[] ) { new ordenar1().printElementos(); } } ________________________________________________________________________ 21 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Otra aplicación muy usual es la Búsqueda Binaria, que es la búsqueda en este caso de Strings en un ArrayList. El algoritmo BB localiza un Object en una List(ya sea LinkedList, Vector y ArrayList). Si el objeto es encontrado, el indice (posicion relativa a cero) de un Object es retornado. Si el Object no es encontrado, BB retorna un valor negativo. Aplicación(Busqueda Binaria) // Usando BB import java.util.*; public class BBinariaDemo { private String colores[] = { "rojo", "blanco", "azul", "negro","amarillo","purpura", "verde", "rosado" }; private ArrayList aList; // referencia a ArrayList public BBinariaDemo() { aList = new ArrayList( Arrays.asList( colores ) ); /*llama al método de Collection,sort para ordenar aList en orden ascendente*/ Collections.sort( aList ); // ordena la ArrayList System.out.println( "ArrayList Ordenada: " + aList ); } public void printResBB() { printResBBAyuda( colores[ 3 ] ); // primer item printResBBAyuda( colores[ 0 ] ); // mitad item printResBBAyuda( colores[ 7 ] ); // ultimo item printResBBAyuda( "ahora" ); // no existe printResBBAyuda( "si" ); // no existe printResBBAyuda( "no" ); // no existe } private void printResBBAyuda( String key ) { int resultado = 0; System.out.println( "\nBusqueda para: " + key ); resultado = Collections.binarySearch( aList, key ); System.out.println( ( resultado >= 0 ? "Encontrado el indice " + resultado: "No Encontrado (" + resultado + ")" ) ); } public static void main( String args[] ) { new BBinariaDemo().printResBB(); } } La ejecución es: ArrayList Ordenada:[amarillo, azul, blanco, negro, purpura, rojo, rosado, verde] Busqueda para: negro Encontrado en indice 3 Busqueda para rojo Encontrado en indice 5 Busqueda para: rosado Encontrado en indice 6 Busqueda para ahora ________________________________________________________________________ 22 Ingeniería en Computación, Universidad de La Serena Programación OO No Encontrado Busqueda para No Encontrado Busqueda para No Encontrado Colecciones Dr. Eric Jeltsch F. (-1) si (-8) no (-5) HashTable Los lenguajes de POO hacen muy fácil el crear nuevos tipos, y por lo tanto es necesario manejar estos elementos eficientemente, esto es, como almacenar y recuperar objetos. Almacenar y recuperar información con arrays es eficiente en la medida que los datos estén asociados a ciertas claves, y estas a su vez sean únicas, para evitar colisiones. Como Ud. ya lo ha notado esta forma de asociar la información no es la más apropiada. La idea fundamental que se propone es la base de la técnica llamada hashing. En la asignatura de Diseño y Análisis de Algoritmos (DAA) existe una variedad de técnicas para salvar esta situación de colisiones, sin embargo la solución que implementa Java a través de la clase Hashtable (del paquete java.util), es la solución más popular, y que se refiere a tener en cada celda de la tabla un hash ”bucket”, típicamente una lista enlazada de todos los elementos. El factor que afecta la realización de este esquema es llamado factor de carga, concepto ya visto en el curso antes mencionado, y que se refiere a la razón del número de celdas ocupadas en la tabla hashing y el tamaño de la tabla. En resumen un Hashtable es una estructura de datos que permite localizar elementos almacenados mediante una llave o clave asociada. Con un array podría acceder a un elemento rápidamente con un índice entero, el problema es que la clave sólo puede ser un entero. Por otra parte, con un Hashtable es posible asociar una llave a un elemento para después utilizarla a fin de localizar el elemento. No olvidar que como clave puede utilizar cualquier tipo de objetos desde la patente del auto hasta otras más sofisticadas. Algunas herramienta básicas Para construir un Hashtable con Java, primero debe crear un objeto Hashtable con el constructor de esta clase. Después puede agregar nuevos elementos al hashtable mediante el método put(poner) de la clase Hashtable, cuyo formato se visualiza así: Object put(Object clave, Object valor); Para extraer el elemento por medio de la llave, debe llamar el método get(extraer) de la clase Hashtable, el método get() devuelve un Object, que debe convertir a la clase original del elemento. Object get(Object clave); Para eliminar un elemento de un Hashtable, debe llamar al método remove() de esta clase, cuyo formato es: Object remove(Object clave); Aplicación (hashing_alumnos) import java.util.*; // clase para almacenar los datos de los alumnos class RegAlumno { ________________________________________________________________________ 23 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. String nombre; String telefono; float promedio; RegAlumno(String nuevo_nombre, String nuevo_telefono, float nuevo_promedio) { nombre = new String(nuevo_nombre); telefono = new String(nuevo_telefono); promedio = nuevo_promedio; } public String toString() { return("Nombre: " + nombre + "\nTelefono No: " + telefono + "\nPromedio: " + promedio); } } public class hashing_alumnos { public static void main(String args[]) { Hashtable lista_alumnos = new Hashtable(); lista_alumnos.put("575-17-2351", new RegAlumno("Juan Pérez", "555-2310", 4.0f)); lista_alumnos.put("243-67-0201", new RegAlumno("Pedro López", "555-6104", 3.1f)); lista_alumnos.put("923-55-9124", new RegAlumno("José Martínez","555-3434", 2.7f)); lista_alumnos.put("123-95-7934", new RegAlumno("María Sánchez","555-0017", 3.9f)); // extraer un alumno en particular RegAlumno alumno = (RegAlumno) lista_alumnos.get("243-67-0201"); System.out.println("Alumno número 243-67-0201:"); System.out.println(alumno); } } La salida es: Alumno número 243-67-0201: Nombre: Pedro López Telefono: 555-6104 Promedio: 3.1 Map ________________________________________________________________________ 24 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Por último veamos la interface llamada Map, que asocia claves a valores que no pueden contener claves repetidas ( es decir, toda clave puede estar en correspondencia con un solo elemento, concepto matemático conocido como función inyectiva). Aplicación(MapDemo) /* Usando HashMap para almacenar el número de palabras que comienzan con una letra dada*/ import java.util.*; public class MapDemo { private static String nombres[] = { "uno", "dos", "tres", "cuatro", "cinco", "seis","siete", "dos", "diez", "cuatro" }; public MapDemo() { /* Las clases HashMap y TreeMap implementan la interface Map. HashMap almacena los elementos en una HashTable y TreeMap almacena los elementos en un Tree. La interface SortedMap extiende a Map y mantiene sus elementos ordenados. La aplicación siguiente usa HashMap para contar el número de String que comienzan con una letra dada.*/ HashMap m = new HashMap();//construye el HashMap m Integer i; /* el ciclo usa m para almacenar el número de palabras en nombres que comienzan con una letra dada, el método get recupera el Character(la primera letra de un String en nombres) desde el HasMap. Si el HashMap no contiene una correspondencia con Character, get entrega null. Si por el contrario existe correspondencia, el valor es retornado como un objeto. El valor es “cast” a integer y asignado a i. Si i es null el Character no esta en la HasMap*/ for ( int k = 0; k < nombres.length; k++ ) { i = ( Integer ) m.get( new Character( nombres[ k ].charAt( 0 ) ) ); /* Si la clave no esta en map entonces entrega el valor uno de otra manera incrementa su valor por 1*/ if ( i == null ) m.put( new Character( nombres[ k ].charAt( 0 ) ), new Integer( 1 ) ); else m.put( new Character( nombres[ k ].charAt( 0 ) ), new Integer( i.intValue() + 1 ) ); } letra: System.out.print( "\nnumero de palabras que comienzan con " + "la " ); printMap( m ); } public void printMap( Map mapRef ) { System.out.println( mapRef.toString() ); System.out.println( "size: " + mapRef.size() ); System.out.println( "isEmpty: " + mapRef.isEmpty() ); ________________________________________________________________________ 25 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. } public static void main( String args[] ) { new MapDemo(); } } La ejecución es: numero de palabras que comienzan con la letra: {d=3, c=3, u=1, t=1, s=2} size: 5 isEmpty: false Algunas observaciones a tener en cuenta: Java no permite que se haga uso inadecuado de los objetos que se colocan en una colección. Si se introduce un auto en una colección de animales mamíferos, al intentar extraer el auto se obtendrá una excepción. Y del mismo modo, si se intenta colocar un molde al coche que se está sacando de la colección para convertirlo en animal mamífero, también se obtendrá una excepción en tiempo de ejecución. El ejemplo ilustra estas circunstancias. import java.util.*; class Auto { private int numAuto; Auto( int i ) { numAuto = i; } void print() { System.out.println( "Auto nº"+numAuto ); } } class Barco { private int numBarco; Barco( int i ) { numBarco = i; } void print() { System.out.println( "Barco nº"+numBarco ); } } public class javaDemo1 { public static void main( String args[] ) { Vector autos = new Vector(); for( int i=0; i < 7; i++ ) autos.addElement( new Auto( i ) ); // No hay ningun problema en añadir un barco a los coches autos.addElement( new Barco( 7 ) ); for( int i=0; i < autos.size(); i++ ) (( Auto )autos.elementAt( i ) ).print(); // El barco solamente es detectado en tiempo de ejecucion } } ________________________________________________________________________ 26 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Como se puede observar, el uso de un Vector es muy sencillo: se crea uno, se colocan elementos en él con el método addElement() y se recuperan con el método elementAt(). Vector tiene el método size() que permite conocer cuántos elementos contiene, para evitar el acceso a elementos fuera de los límites del Vector y obtener una excepción. Las clases Auto y Barco son distintas, no tienen nada en común excepto que ambas son Object. Si no se indica explícitamente de la clase que se está heredando, automáticamente se hereda de Object. La clase Vector maneja elementos de tipo Object, así que no solamente es posible colocar en ella objetos Auto utilizando el método addElement(), sino que también se pueden colocar elementos de tipo Barco sin que haya ningún problema ni en tiempo de compilación ni a la hora de ejecutar el programa. Cuando se recupere un objeto que se supone es un Auto utilizando el método elementAt() de la clase Vector, hay que colocar un moldeo para convertir el objeto Object en el Auto que se espera, luego hay que colocar toda la expresión entre paréntesis para forzar la evaluación del moldeo antes de llamar al método print() de la clase Auto, sino habrá un error de sintaxis. Posteriormente, ya en tiempo de ejecución, cuando se intente moldear un objeto Barco a un Auto, se generará una excepción, tal como se puede comprobar en las siguientes líneas, que reproducen la salida de la ejecución del ejemplo: %java javaDemo1 Coche nº0 Coche nº1 Coche nº2 Coche nº3 Coche nº4 Coche nº5 Coche nº6 java.lang.ClassCastException: Barco at javaDemo1.main(javaDemo1.java:54) Lo cierto es que esto es un fastidio, porque puede ser la fuente de errores que son muy difíciles de encontrar. Si en una parte, o en varias partes, del programa se insertan elementos en la colección, y se descubre en otra parte diferente del programa que se genera una excepción es porque hay algún elemento erróneo en la colección, así que hay que buscar el sitio donde se ha insertado el elemento de la discordia, lo cual puede llevar a intensas sesiones de depuración. Así que, para enredar al principio, es mejor empezar con clases estandarizadas en vez de aventurarse en otras más complicadas, a pesar de que estén menos optimizadas. Sin embargo, al considerar la clase siguiente ________________________________________________________________________ 27 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. public class javaDemo1 { public static void main( String args[] ) { Vector coches = new Vector(); for( int i=0; i < 7; i++ ) coches.addElement( new Coche( i ) ); // No hay ningun problema en añadir un barco a los coches coches.addElement( new Barco( 7 ) ); Enumeration e = coches.elements(); while( e.hasMoreElements() ) (( Coche )e.nextElement()).print(); // El barco solamente es detectado en tiempo de ejecucion } } notamos que con la modificación del JavaDemo1, en que se utilizaba el método elementAt() para seleccionar cada uno de los elementos. Ahora se utiliza una enumeración para el mismo propósito, y el único código interesante de este nuevo ejemplo es el cambio de las líneas del ejemplo original for( int i=0; i < coches.size(); i++ ) (( Coche )coches.elementAt( i ) ).print(); por estas otras en que se utiliza la enumeración para recorrer la secuencia de objetos while( e.hasMoreElements() ) (( Coche )e.nextElement()).print(); la gracia de Enumeration es que no hay que preocuparse del número de elementos que contenga la colección, ya que del control sobre ellos se encargan los métodos hasMoreElements() y nextElement(). Las colecciones estándar de Java contienen el método toString(), que permite obtener una representación en forma de String de sí mismas, incluyendo los objetos que contienen. Dentro de Vector, por ejemplo, toString() va saltando a través de los elementos del Vector y llama al método toString() para cada uno de esos elementos. import java.util.*; public class javaDemo2 { public String toString() { return( "Direccion del objeto: "+this+"\n" ); } public static void main( String args[] ) { Vector v = new Vector(); for( int i=0; i < 10; i++ ) v.addElement( new javaDemo2() ); System.out.println( v ); } } ________________________________________________________________________ 28 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. El ejemplo no puede ser más sencillo, simplemente crea un objeto de tipo javaDEmo2 y lo imprime; sin embargo, a la hora de ejecutar el programa lo que se obtiene es una secuencia infinita de excepciones. Lo que está pasando es que cuando se le indica al compilador: "Direccion del objeto: "+this el compilador ve un String seguido del operador + y otra cosa que no es un String, así que intenta convertir this en un String. La conversión la realiza llamando al método toString() que genera una llamada recursiva, llegando a llenarse la pila, de ahí el mensaje. Si realmente se quiere imprimir la dirección del objeto en este caso, la solución pasa por llamar al método toString() de la clase Object. Así, si en vez de this se coloca super.toString(), el ejemplo funcionará. ________________________________________________________________________ 29 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Las cajas punteadas representan interfaces y las sólidas representan clases normales, excepto aquellas en que el texto interior comienza por Abstract, que representan clases abstractas. Las flechas indican que una clase puede generar objetos de la clase a la que apunta; por ejemplo, cualquier Collection puede producir un Iterator, mientras que una List puede producir un ListIterator (al igual que un Iterator normal, ya que List hereda de Collection). Los interfaces que tienen que ver con el almacenamiento de datos son: Collection, Set, List y Map. Normalmente, un programador creará casi todo su código para entenderse con estos interfaces y solamente necesitará indicar específicamente el tipo de datos que se están usando en el momento de la creación. Por ejemplo, una lista se puede crear de la siguiente forma: List lista = new LinkedList(); Desde luego, también se puede decidir que lista sea una lista enlazada, en vez de una lista genérica, y precisar más el tipo de información de la lista. Lo bueno, y la intención, del uso de interfaces es que si ahora se decide cambiar la implementación de la lista, solamente es necesario cambiar el punto de creación, por ejemplo: List lista = new ArrayList(); el resto del código permanece invariable. Por lo tanto, a la hora de sacar provecho del diagrama antes dado, es suficiente con lo que respecta a los interfaces y a las clases concretas. Lo normal será construir un objeto correspondiente a una clase concreta, moldearlo al correspondiente interfaz y ya usas ese interfaz en el resto del código. El siguiente ejemplo es muy simple y consiste en una colección de objetos String que se imprimen. ________________________________________________________________________ 30 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. import java.util.*; public class javaDemo3 { public static void main( String args[] ) { Collection c = new ArrayList(); for( int i=0; i < 10; i++ ) c.add( Integer.toString( i ) ); Iterator it = c.iterator(); while( it.hasNext() ) System.out.println( it.next() ); } } Notar que, como las nuevas colecciones forman parte del paquete java.util, no es necesario importar ningún paquete adicional para utilizarlas. A continuación se comentan segmentos interesantes del código del ejemplo. La primera línea del método main() crea un objeto ArrayList y lo “moldea” a una Collection. Como este ejemplo solamente utiliza métodos de Collection, cualquier objeto de una clase derivada de Collection debería funcionar, pero se ha cogido un ArrayList porque es el caballo de batalla de las colecciones y viene a tomar el relevo al Vector. El método add(), como su nombre sugiere, coloca un nuevo elemento en la colección. Sin embargo, la documentación indica claramente que add() "asegura que la colección contiene el elemento indicado". Esto es para que un Set tenga significado, ya que solamente añadirá el elemento si no se encuentra en la colección. Con un ArrayList, o cualquier otra lista ordenada, add() significa siempre "colocarlo dentro". Recordar que en Set (interfaz), cada elemento que se añada a un Set debe ser único, ya que el otro caso no se añadirá porque el Set no permite almacenar elementos duplicados. Los elementos incorporados al Conjunto deben tener definido el método equals(), en aras de establecer comparaciones para eliminar duplicados. Set tiene el mismo interfaz que Collection, y no garantiza el orden en que se encuentren almacenados los objetos que contenga. Finalmente, todas las colecciones pueden producir un Iterator invocando al método iterator(). Un Iterator viene a ser equivalente a una Enumeration. En el ejemplo se utiliza un Iterator para desplazarse por la colección e ir imprimiendo cada uno de sus elementos. ________________________________________________________________________ 31 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Colecciones A continuación se indican los métodos que están disponibles para las colecciones, es decir, lo que se puede hacer con un Set o una List, aunque las listas tengan funcionalidad añadida que ya se verá, y Map no hereda de Collection, así que se tratará aparte. boolean add( Object ) Asegura que la colección contiene el argumento. Devuelve false si no se puede añadir el argumento a la colección boolean addAll( Collection ) Añade todos los elementos que se pasan en el argumento. Devuelve true si es capaz de incorporar a la colección cualquiera de los elementos del argumento void clear() Elimina todos los elementos que componen la colección boolean contains( Object ) Verdadero si la colección contiene el argumento que se pasa como parámetro boolean isEmpty() Verdadero si la colección está vacía, no contiene elemento alguno Iterator iterator() Devuelve un Iterator que se puede utilizar para desplazamientos a través de los elementos que componen la colección boolean remove( Object ) Si el argumento está en la colección, se elimina una instancia de ese elemento y se devuelve true si se ha conseguido boolean removeAll( Collection ) Elimina todos los elementos que están contenidos en el argumento. Devuelve true si consigue eliminar cualquiera de ellos boolean retainAll( Collection ) Mantiene solamente los elementos que están contenidos en el argumento, es lo que sería una intersección en la teoría de conjuntos. Devuelve verdadero en caso de que se produzca algún cambio int size() Devuelve el número de elementos que componen la colección ________________________________________________________________________ 32 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Object[] toArray() Devuelve un array conteniendo todos los elementos que forman parte de la colección. Este es un método opcional, lo cual significa que no está implementado para una Collection determinada. Si no puede devolver el array, lanzará una excepción de tipo UnsupportedOperationException /** * Este ejemplo muestra lo que se puede hacer con las Collections que * se han incorporado al JDK 1.2 */ import java.util.*; public class javaDemo5 { // Rellena la Colección con el número de elementos que se especifica // en 'tamano', comenzando a partir del elemento que indica el // parámetro 'primero' public static Collection fill( Collection c,int primero,int tamano ) { for( int i=primero; i < primero+tamano; i++ ) c.add( Integer.toString( i ) ); return( c ); } // También rellena la Colección con el número de elementos que se // indique en el parámetro 'tamano', pero se inicia desde el // elemento 0 public static Collection fill( Collection c,int tamano ) { return( fill( c,0,tamano ) ); } // En este caso se rellena la Colección comenzando en el elemento // 0 y rellenando 10 elementos public static Collection fill( Collection c ) { return( fill( c,0,10 ) ); } // Crea una estructura de datos y la moldea a Colección public static Collection nuevaColeccion() { // Se utiliza un ArrayList por simplicidad, pero se puede ver // como una Collection genérica en cualquier lugar del // programa return( fill( new ArrayList() ) ); } // Rellena una Colección con un rango de valores public static Collection nuevaColeccion( int primero,int tamano ) { return( fill( new ArrayList(),primero,tamano ) ); } ________________________________________________________________________ 33 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. // Se desplaza a través de una Lista utilizando un Iterador public static void print( Collection c ) { for( Iterator x=c.iterator(); x.hasNext(); ) System.out.print( x.next()+" " ); System.out.println(); } public static void main( String args[] ) { Collection c = nuevaColeccion(); c.add( "diez" ); c.add( "once" ); print( c ); // Busca los elementos máximo y mínimo; esto puede hacerse // de diversas formas, dependiendo de como esté implementado // el interfaz Comparable System.out.println( "Collections.max(c) = "+ Collections.max( c ) ); System.out.println( "Collections.min(c) = "+ Collections.min( c ) ); // Añade una Colección a otra Colección c.addAll( nuevaColeccion() ); print( c ); c.remove( "3" ); // Elimina el primero print( c ); c.remove( "3" ); // Elimina el segundo print( c ); // Elimina todos los componentes que esten en la Colección // que se pasa como argumento c.removeAll( nuevaColeccion() ); print( c ); c.addAll( nuevaColeccion() ); print( c ); // Mira si un elemento determinado está en la Colección System.out.println( "c.contains(\"4\") = "+c.contains("4") ); // Mira si la SubColección está en la Colección base System.out.println( "c.containsAll( nuevaColeccion() ) = "+ c.containsAll( nuevaColeccion() ) ); Collection c2 = nuevaColeccion( 5,3 ); // Mantiene todos los elementos que están en las colecciones // 'c' y 'c2'. Hace una intersección de las dos colecciones c.retainAll( c2 ); print( c ); // Elimina de la colección 'c' todos los elementos que se // encuentran también en la colección 'c2' c.removeAll( c2 ); System.out.println( "c.isEmpty() = "+c.isEmpty() ); c = nuevaColeccion(); print( c ); // Se eliminan todos los elementos c.clear(); ________________________________________________________________________ 34 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. System.out.println( "Despues de c.clear():" ); print( c ); } } Vector Stack public Stack() public Object push(Object obj) public Object pop() public Object peek() public int search(Object obj) public boolean empty() Fig.: la clase Stack Stack Un Stack es una Pila, o una colección de tipo LIFO (last-in, first-out). Es decir, lo último que se coloque en la pila será lo primero que se saque. Como en todas las colecciones de Java, los elementos que se introducen y sacan de la pila son Object, así que hay que tener cuidado con el “molde” a la hora de sacar alguno de ellos. ________________________________________________________________________ 35 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Los diseñadores de Java, en vez de utilizar un Vector como bloque para crear un Stack, han hecho que Stack derive directamente de Vector, así que tiene todas las características de un Vector más alguna otra propia ya del Stack. El ejemplo siguiente, es una demostración muy simple del uso de una Pila que consisten en leer cada una de las líneas de un array y colocarlas en un String. Cada línea en el array diasSemana se inserta en el Stack con push() y posteriormente se retira con pop(). Para ilustrar una afirmación anterior, también se utilizan métodos propios de Vector sobre el Stack. Esto es posible ya que en virtud de la herencia un Stack es un Vector, así que todas las operaciones que se realicen sobre un Vector también se podrán realizar sobre un Stack, como por ejemplo, elementAt(). /** * Este ejemplo es una demostracion muy sencilla de la utilizacion de * una Pila o Stack */ import java.util.*; public class javaDemo7 { static String diasSemana[] = { "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo" }; public static void main( String args[] ) { Stack pila = new Stack(); for( int i=0; i < diasSemana.length; i++ ) pila.push( diasSemana[i]+" " ); System.out.println( "pila = "+pila ); // Tratando la Pila como un Vector: pila.addElement( "Esta es la ultima linea" ); // Se imprime el elemento 5 (sabiendo que la cuenta empieza en 0) System.out.println( "Elemento 5 -> "+pila.elementAt( 5 ) ); System.out.println( "Elementos introducidos:" ); while( !pila.empty() ) System.out.println( pila.pop() ); } } ________________________________________________________________________ 36 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Genericos No se puede ser un programador de Java competente sin entender las partes esenciales de la Biblioteca Java. Los tipos básicos están todos en java.lang, y son parte del lenguaje propiamente dicho. El paquete java.util ofrece colecciones -conjuntos, listas y mapas- y es necesario conocerlo muy bien. El paquete java.io también es importante y no basta con tener de él un conocimiento básico, hace falta profundizar. Por otra parte, la ventaja de los lenguajes de programación orientados a objetos es que permiten reutilizar el código entre aplicaciones. Sin embargo, casi ninguno de estos lenguajes resuelven un problema de alcance mayor, a saber: ¿Cómo diseñar contenedores o estructuras de datos (pilas, listas, colas) que sean genéricas, es decir, que trabajen con cualquier tipo de datos (enteros, caracteres, clases del usuario, etc.)? En C++, esto se resuelve mediante el uso de plantillas. Una plantilla, como su nombre lo indica, es un contenedor que puede construirse para cualquier tipo de datos. Entonces surge la Librería Estándar de Plantillas (STL), que se distribuye con varios compiladores o puede obtenerse gratis. Esta es un conjunto de estructuras de datos muy diversas y de uso común, como pilas, colas, diccionarios, conjuntos y otros. Supongamos que un programador debe desarrollar una clase especial para implementar una pila de enteros. Este programador opta por crear sus propias funciones de empuje y sacado de pila, chequeo de pila vacía y otras. Esa clase puede reutilizarse con otro código que requiere el uso de enteros. Pero supongamos que de repente debe crearse una pila de números reales. ¡El trabajo del programador ha sido en vano! A menos que haya usado la STL, que provee una clase de pila prefabricada que puede instanciarse para cualquier tipo de datos. En código: #include <stl.h> // Primer caso stack<int> pilaEnteros; // Segundo caso stack<float> pilaReales; Es decir, se pone entre signos mayor menor (<>) el tipo de datos, que puede ser incluso uno definido por nosotros; la clase stack contiene funciones miembro que nos dan la funcionalidad de la pila. Basado en este esquema se ha logrado un ahorro sustancial de tiempo y eficiencia en más de un proyecto. Hay que ser justos y señalar que Java tiene una mejor forma de implementar contenedores de objetos genéricos, pero hay que notar que Java es un lenguaje mucho más joven (unos cuatro años de "edad") que C++. En este mismo contexto, digamos que la librería estándar de Java proporciona bastantes colecciones útiles, ya muy potentes en el JDK 1.2, aunque no es un compendio completo. Una de las potencias de C++ son sus librerías, y en concreto la Standard Template Library (STL) que proporciona un conjunto completo de colecciones, así como algoritmos de ordenación y búsqueda que trabajan sobre estas colecciones. Ya la empresa ObjectSpace había creado una Librería Genérica para Java, Java Generic Library (JGL), que se adapto al diseño de la STL, salvando las diferencias que existen entre los dos lenguajes, obviamente. La JGL parece cumplir muchas, sino todas, de las necesidades de una librería de colecciones, al menos en todo lo que se puede sin disponer de un mecanismo como las plantillas, template, de C++. La JGL incluye listas enlazadas, conjuntos, colas, mapas, pilas, secuencias e iteradores, que en algunos casos presentan ________________________________________________________________________ 37 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. decisiones de diseño más inteligentes que las librerías antiguas de Sun; por ejemplo, los métodos en JGL no son nunca final, con lo cual es fácil heredar y sobreescribir estos métodos. La JGL está incluida en algunas distribuciones de Java y ObjectSpace ha puesto la JGL en dominio público, incluida su utilización comercial, en http://www.ObjectSpace.com, sin embargo, ya en la versión 1.5 se encuentre en fase final e incorpora todas las opciones que ahora ofrece la JGL. Para mayor información vea, http://java.sun.com/j2se/1.5.0/docs/guide/language/index.html Se presentan algunas mejoras, respecto de la versión 1.4(textual) Here is a simple example taken from the existing Collections tutorial: // Removes 4-letter words from c. Elements must be strings static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (((String) i.next()).length() == 4) i.remove(); } Here is the same example modified to use generics: // Removes the 4-letter words from c static void expurgate(Collection<String> c) { for (Iterator<String> i = c.iterator(); i.hasNext(); ) if (i.next().length() == 4) i.remove(); } When you see the code <Type>, read it as “of Type”; the declaration above reads as “Collection of String c.” Existe también un tutorial para Generics. http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf Tipo Enumerado: public class Color { // Color value; int _color; // Constructor protected Color (int color) { _color = color; } private static final int _Red = 1; private static final int _White = 2; private static final int _Blue = 3; public static final Color Red = new Color(_Red); public static final Color White = new Color(_White); public static final Color Blue = new Color(_Blue); } // Invocar con: Color miColor = Color.Red; ________________________________________________________________________ 38 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. La solución en Java 5 es mucho más sencilla: public enum Color { Red, White, Blue } // Color miColor = Color.Red; Java 1.5 fue la introducción al campo de lo Generics o programación basado en Template, asimilándose a C++. import java.util.*; import java.util.List; class ListTest { public static void main(String [] args) { List<String> xs = new ArrayList<String>(); xs.add("Shakespeare"); xs.add("Schiller"); xs.add("Goethe"); xs.add("Brecht"); xs.add("Thomas Mann"); String x = xs.get(3); System.out.println(xs); } } Este ejemplo muestra la transformación que tiene un segmento de programa que NO es genérico y otro que sí lo es, usando una forma muy particular de la estructura de control for import java.util.List; import java.util.ArrayList; import java.util.Iterator; class AlteIteration { public static void main(String [] args) { String [] ar = { "Brecht", "Schiller", "Goethe", "Shakespeare", "Thomas Mann" }; List xs = new ArrayList(); for (int i = 0;i < ar.length; i++) { final String s = ar[i]; xs.add(s); } for (Iterator it = xs.iterator(); it.hasNext();) { final String s = (String) it.next(); System.out.println(s.toUpperCase()); ________________________________________________________________________ 39 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. } } } for (Type identifier expr) { body } import java.util.List; import java.util.ArrayList; class NeueIteration { public static void main(String [] args) { String [] ar = { "Brecht", "Schiller", "Goethe", "Shakespeare", "Thomas Mann" }; List<String> xs = new ArrayList<String>(); for (String s:ar) xs.add(s); for (String s:xs) System.out.println(s.toUpperCase()); } } Extiende el modo en que import funciona en Java. Por ejemplo para usar la función ceil() habría que importar primero java.lang.Math y luego escribir: double y = Math.ceil(3.2); // = 4,0 Sin embargo, ahora con Java 5 se podría hacer: double y = ceil(x), ya que se pueden hacer imports del siguiente modo: import static java.lang.Math.ceil; import static java.lang.Math.*; Para mayor información, ________________________________________________________________________ 40 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. http://java.sun.com/docs/books/tutorial/collections/index.html ________________________________________________________________________ 41 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. ________________________________________________________________________ 42 Ingeniería en Computación, Universidad de La Serena Programación OO Colecciones Dr. Eric Jeltsch F. Java 5.0 in a Nutshell, http://java.sun.com/developer/technicalArticles/releases/j2se15/ ________________________________________________________________________ 43 Ingeniería en Computación, Universidad de La Serena