Lenguaje de Programación Orientado a Objetos Unidad 3. Enumeraciones 3.1 Tipos de datos enumeración (enum) A partir de la versión de Java SE 5.

0 se pueden definir tipos de datos enumerados (enum) o enumeraciones que constan de diferentes elementos, especifican diversos valores por medio de identificadores y son definidos por el programador mediante la palabra reservada enum; también tienen un número finito de elementos y valores nombrados; por ejemplo, la siguiente sentencia: enum Notas {A, B, C, D, E}; La sentencia anterior define Notas como un tipo enumerado (enum); los valores de sus elementos son A, B, C, D y E cuyos valores se denominan constantes de enumeración o enum, se encierran entre llaves ({}) y se separan por comas; las constantes dentro de un tipo enum deben ser únicas; por ejemplo, el tipo de datos DEPORTES: enum DEPORTES {TENIS, ESQUÍ, FUTBOL, BALONCESTO, GOLF}; Define el tipo DEPORTES como enum y sus valores son las constantes similares: TENIS, ESQUÍ, FUTBOL, BALONCESTO y GOLF. Cada enum es un tipo especial de clase y los valores que le pertenecen son objetos de la clase. Después de definir un tipo de dato enum, se pueden declarar variables con referencia a tal tipo; por ejemplo: DEPORTES miDeporte; y se le puede asignar un valor a la variable: miDeporte=DEPORTES.TENIS; Una variable de tipo DEPORTES sólo puede contener uno de los valores listados en la declaración del tipo de dato o el valor especial null indicando que no se establece ningún valor específico a la variable. 3.2 Enumeraciones (clases enum) El tipo de dato básico enum se define como un conjunto de constantes que se representan como identificadores únicos; cada constante enum dentro de este tipo toma un valor específico denominado ordinal; el de la primera constante enum es 0, el de la segunda es 1, y así sucesivamente; por consiguiente, en el tipo enum: DiasSemana{LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO} El valor ordinal de LUNES es 0 y el valor ordinal de JUEVES es 3. Existe una relación entre los tipos enum y las clases; las enumeraciones son un conjunto de objetos que representan un conjunto relacionado de opciones. Al igual que las clases, todos los tipos enum son de referencia y, analizando a detalle, también son una enumeración en una clase de tipo enum; estas clases pueden tener métodos, constructores y miembros dato, al igual que cualquier otra; en su declaración, como se comentó antes, éste puede contener otros componentes tales como miembros dato: constructores, métodos y campos; además de las constantes enumeradas.

La declaración de una clase enumeración se realiza con la palabra reservada enum y sigue estas reglas: 1. Los tipos enumeración se definen utilizando la palabra reservada enum, en lugar de class. 2. Las constantes enum son implícitamente estáticas (static). 3. Los tipos enum son tácitamente del tipo final, ya que declaran constantes que no pueden modificarse. 4. Una vez que se crea un tipo enumeración se pueden declarar variables referencia de ese tipo, pero no se pueden instanciar objetos utilizando el operador new; si se intenta instanciar un objeto utilizándolo se producirá un error de compilación. 5. Dado lo anterior, si existe constructor de tipo enumeración, éste no puede ser público (public) porque es implícitamente privado (private). El tipo enum tiene asociados un conjunto de métodos que se utilizan para trabajar con tipos enumeración; la tabla 3.1 describe alguno de ellos. Tabla 3.1 Métodos asociados con tipos de datos enum. Método Descripción ordinal() Describe el valor ordinal de una constante enum Devuelve el nombre del valor de enum. Devuelve los valores de un tipo enum en forma de lista.

name() values()

Ejemplo 3.1 Definir la clase Notas de tipo enumerado enum Notas {A, B, C, D, E}; public enum Notas { A (“Escala 90 a 100 puntos”), B (“Escala 80 a 89.99 puntos”), C (“Escala 70 a 79.99 puntos”), D (“Escala 60 a 69.99 puntos”), E (“Escala 0 a 59.99 puntos”); private final String escala; private Notas () { escala=” ”; } private Notas (String cad) { escala=cad; }

public String leerEscala() { return escala; } } En la declaración anterior, el tipo enumerado Notas contiene las constantes A, B, C, D, y E; una constante de nombre escala, del tipo String; y dos constructores con igual nombre que la clase y el método leerEscala. Especificaciones de la clase Notas: 1. La sentencia: A (“Escala de 90 a 100 puntos”) crea el objeto Notas utilizando el constructor con parámetros, con la cadena “Escala 90 a 100 puntos” y asigna ese objeto a la variable referencia A. 2. El método leerEscala se utiliza para devolver la cadena contenida en el objeto. 3. No es necesario especificar el modificador private en la cabecera del constructor ya que cada uno es, implícitamente, privado; por consiguiente, los dos constructores del tipo enum también se podrían escribir así: Notas() { escala=” “; } Notas (String cad) { escala=cad; } Ejercicio 3.1 El programa EnumEjemplo muestra el funcionamiento del tipo enumeración Notas. Public class EnumEjemplo { public static void main (String[] a) { System.out.println(“Escala de notas”); for (Notas nt: Notas.values()) System.out.println(nt+ “ “+ nt.leerEscala()); System.out.println(); } } Se define la clase EnumEjemplo y, al ejecutarse, el bucle for each utiliza el método values() que se asocia con los tipos enum para recuperar las constantes de numeración como una lista; el método leerEscala se utiliza para recuperar la cadena contenida en cada objeto Notas. La ejecución del programa producirá: Escala de notas A Escala 90 a 100 puntos

B Escala 80 a 89.99 puntos C Escala 70 a 79.99 puntos D Escala 60 a 69.99 puntos E Escala 0 a 59.99 puntos UNIDAD 4 PARTE 1 Lenguaje de Programación Orientado a Objetos Unidad 4. Clases abstractas e interfaces Esta unidad profundiza el concepto de clase y uno de sus tipos especiales: la abstracta, que agrupa características comunes de otras clases y, de la cual, no se puede instanciar objetos. Otra estructura relacionada con las clases son las interfaces; éstas especifican las operaciones que deberán definirse en las clases que la implementen. 4.1 Aspectos de diseño relacionados con el uso y desarrollo de interfaces Java posee una notación para describir la apariencia externa de una clase, a la cual se le llama interfaz. La descripción de una interfaz es semejante a la de una clase, sólo que sin los cuerpos de los métodos. No se debe confundir el uso que se hace aquí de la palabra “interfaz” con la misma palabra que se utiliza en el término interfaz gráfica de usuario (GUI). Las interfaces tienen dos usos:  En el diseño  Para promover la interoperabilidad Interfaces para el diseño Con frecuencia se hace hincapié sobre la importancia del diseño durante la planeación inicial de un programa. Para ello hay que diseñar todas las clases del mismo. Una forma de documentar dicho diseño es escribir en español una especificación de los nombres de las clases y sus métodos. Pero también es posible escribir esta descripción en Java. Sintaxis acceso interface NombreInterface { constante1; … constante2; tipo1 nombreMetodo1 (argumentos); … Tipon nombreMetodon (argumentos); } acceso visibilidad de la interfaz definida, normalmente public.

println(“¡¡¡Alarma del barco pasajero!!!”). class NombreClase implements NombreInterfaz { // // // } La clase que implementa la interfaz tiene que especificar el código (la implementación) de cada uno de sus métodos. private int numeroCamas=101. todos tienen como comportamiento común msgeSocorro() y alarma(). Ejemplo Considérese una jerarquía de barcos. } 4.out. definición de atributos definición de métodos de la clase definición de métodos de la interfaz . utiliza una sintaxis similar a la derivación o extensión de una clase. de no hacerlo.println(“Se crea objeto BarcoPasaje. void msgeSocorro (String av). PortaAvion y Pesquero implementan la interfaz Barco y además definen sus métodos: class BarcoPasaje implements Barco { private int eslora. la clase se convierte en abstracta y debe declararse abstract. con la palabra reservada implements en lugar de extends.out. el cual se realiza en cada una de ellas y se conoce como implementación de interfaz. public BarcoPasaje() { System.Ejemplo public interface Barco { void alarma (). esto es una forma de obligar a que cada método de la interfaz se implemente. } public void alarma() { System.2 Implementación de interfaces La interfaz especifica el comportamiento común que tiene un conjunto de clases.”). así que las clases BarcoPasaje.

”). private String nombre.} public void msgeSocorro(String av) { alarma().println(“Se crea objeto Barco Pesquero. } public void alarma() { System.out. System.println(“Se crea el objeto PortaAviones.println(“¡¡¡SOS SOS!!! ” + av). private double potencia. } public void msgeSocorro(String av) { System. private int tripulacion. System.println(“¡¡¡marineros a sus puestos!!!”). } } class PortaAvion implements Barco { private int aviones=19. public PortaAvión (int marinos) { tripulacion=marinos. System. } public void alarma() . } } class Pesquero implements Barco { private int eslora.out.”). public Pesquero (String nom) { nombre=nom.out.out.println(“¡¡¡SOS SOS!!! ”+ av).out. private int pescadores.

así. no permite la herencia múltiple. es como la herencia.{ System. una clase si puede implementar más de una interfaz y tener el comportamiento común de varias de ellas.out.println(“¡¡¡Alarma nombre + “!!!!”). sencillamente se escriben las interfaces separadas por comas a continuación de la palabra reservada implements. Por lo demás. Se está diciendo “La interfaz contiene la apariencia. Interfaz2. } public void msgeSocorro(String av) { System. la clase tiene que implementar los métodos de todas. } } Múltiples interfaces Java no permite que una clase derive de dos o más clases. se usa la palabra clave implements. ”+ av). Clases abstractas e interfaces Para hacer una clase que se ajuste a una interfaz particular (o a un grupo de interfaces). para esto. …. sin embargo.out. es decir. Sintaxis class NombreClase implements Interfaz1.println(“¡¡¡SOS SOS!!!. Interfazn { // … } UNIDAD 4 PARTE 2 Lenguaje de Programación Orientado a Objetos Unidad 4. El diagrama del ejemplo de los instrumentos lo muestra: desde el pesquero “+ . pero ahora voy a decir cómo funciona”.

esa implementación se convierte en una clase ordinaria que puede extenderse de forma normal. Sintaxis class NombreClase implements Interfaz1. una clase si puede implementar más de una interfaz y tener el comportamiento común de varias de ellas. la clase tiene que implementar los métodos de todas. sencillamente se escriben las interfaces separadas por comas a continuación de la palabra reservada implements. no permite la herencia múltiple. así. para esto. Interfaz2. …. sin embargo. Múltiples interfaces Java no permite que una clase derive de dos o más clases.Una vez implementada una interfaz. es decir. Interfazn { // … } .

las interfaces pueden heredarse tanto como se precise. Sintaxis interface SuperBase1 {…} interface Base1 extends SuperBase1 {…} interface Base2 extends SuperBase1 {…} interface ComúnDerivado extends Base1. de forma que los métodos sean heredados. también se utiliza la palabra reservada extends para especificar su herencia. a diferencia de las clases que sólo pueden heredar de una clase base (herencia simple). y después las interfaces. Base2 {…} . (Sino. Cuando se combina una clase concreta con interfaces de esta manera. hay que poner primero la clase concreta. el compilador dará error. y como en las clases.) UNIDAD 4 PARTE 3 Lenguaje de Programación Orientado a Objetos Unidad 4.Ejemplo Se puede ver que Héroe combina la clase concreta PersonajeDeAcción con las interfaces PuedeLuchar. Clases abstractas e interfaces Herencia en interfaces Es importante recordar que las interfaces se pueden organizar de forma jerárquica. PuedeNadar y PuedeVolar.

el método compareTo debe ser capaz de comparar dos objetos y regresar un valor que indique si x o y es más grande. } Esto significa que cualquier clase que implementa la interfaz Comparable requiere tener el método compareTo. Éste se implementa en Dragon. Cuando se ejecute x.compareTo(y). y también se pueden combinar varias interfaces en una nueva interfaz gracias a la herencia. En ambos casos se consigue una nueva interfaz. y el método debe tomar como parámetro un objeto y regresar un entero.Se pueden añadir nuevas declaraciones de método a una interfaz haciendo uso de la herencia. como se ve en el ejemplo siguiente: MonstruoPeligroso es una simple extensión de Monstruo que produce una nueva interfaz. cero si son iguales y un número positivo si x es mayor. Interfaz Comparable La interfaz Comparable se muestra a continuación: public interface Comparable { int compareTo(Object other). Suponiendo que se quiere usar el método sort de la clase Arrays para ordenar un arreglo de objetos Empleado. Entonces la clase Empleado debe implementar la interfaz Comparable. class Empleado implements Comparable . Vampiro es una extensión de MonstruoPeligroso y Letal. El método regresa un número negativo si x es más pequeña que y.

compareTo(a[j])>0) { //reordenar a[i] y a[j] } El compilador debe saber que a[i] realmente tiene un método compareTo. El método compareTo regresa -1 si el salario del primer empleado es menor que el del segundo. debe implementar la interfaz java.edad) return -1. La serialización es necesaria para trasportar los argumentos y los valores de retorno. public int compareTo(Object otroObjeto) { Empleado otro=(Empleado)otroObjeto. if (edad<otro. La serialización es una característica añadida al lenguaje Java para dar soporte a  La invocación remota de objetos (RMI)  La persistencia La invocación remota de objetos permite a los objetos que se localizan en otras computadoras comportarse como si estuvieran en la propia máquina. mediante la deserialización. if (edad>otro. Si a es un arreglo de objetos cuya clase implementa Comparable. sin que se tenga que implementar ningún método). Para que un objeto sea serializable. ahora la clase Empleado necesita suministrar el método compareTo.io.edad) return 1. Suponiendo que se quiere comparar a los empleados por su salario. .Por supuesto. En algún lugar en el método sort. el compilador necesita verificar que realmente exista el método. entonces se asegura la existencia del método.Serializable (que lo único que hace es marcar el objeto como serializable. Después. porque cada clase que implementa la interfaz Comparable debe suministrar el método. Interfaz Serializable La serialización de un objeto consiste en generar una secuencia de bytes lista para su almacenamiento o transmisión. ¿Por qué no puede la clase Empleado simplemente proveer un método compareTo sin implementar la interfaz Comparable? La razón es que cuando se realiza la invocación de un método en Java. el estado original del objeto se puede reconstruir. habrá sentencias como estas: if( a[i]. en caso de que sean iguales regresa 0 o 1 si el salario del segundo es menor. return 0. } Así que una clase que utiliza el método sort para ordenar un arreglo de objetos debe implementar el método compareTo.

Un ejemplo de una clase serializable se muestra a continuación: import java. private double deuda. Un objeto se puede serializar si implementa la interfaz Serializable.deuda=deuda. this.io.telefono=telefono. Esta interfaz no declara ningún método. La serialización permite guardar el estado de un componente en disco.io.nombre=nombre. } } import java. El estado de un componente es configurado durante el diseño. this. "+email+". . public class Contacto implements Serializable{ private String nombre. private String telefono. String email.La persistencia es una característica importante de los JavaBeans.io. se trata de una interfaz vacía.Serializable. abandonar el Entorno Integrado de Desarrollo (IDE) y restaurar el estado del componente cuando se vuelve a ejecutar el IDE. this. } public String toString(){ return nombre+". "+telefono+ "+grupo+". public class InterfazSerializable { /** * @param args the command line arguments */ public static void main(String[] args) {   ". this. String direccion. int grupo.email=email. this. "+direccion+". String telefono. "+deuda. public Contacto(String nombre.grupo=grupo. import java.direccion=direccion. private String email. Todos los tipos primitivos en Java son serializables por defecto (igual que los arreglos y varios tipos estándar).* public interface Serializable {} Para que un objeto sea serializable todos sus atributos deben ser serializables. private int grupo.*. double deuda){ this. private String direccion.

readObject().} try{ //espera la pulsación de una tecla System.obj")). 50000). try { "5554552913".out. el proceso de deserialización consiste en la lectura del archivo “contacto.obj” almacena los datos en . "jesus@gmail.writeObject("Datos del contacto\n").println(ex). } catch(Exception e){} } } En este ejemplo la serialización consiste en abrir un archivo “contacto.obj” y escribir los objetos definidos como serializables.readObject(). //Cerrar el archivo entrada.out. salida.Contacto contacto=new Contacto("Jesús". 1.} catch (ClassNotFoundException ex) { System. Contacto obj1=(Contacto)entrada. Por otro lado.read().println(str+" "+obj1). //Serialización //Abrir el archivo ObjectOutputStream salida=new ObjectOutputStream FileOutputStream("contacto. El archivo con los objetos serializados “contacto. (new //Deserialización //Abrir el archivo ObjectInputStream entrada=new ObjectInputStream(new FileInputStream("contacto. "Av. //Imprimir los datos del archivo System.com". 5 de Mayo".in.close(). //Cerrar el archivo salida.obj” y mostrarlos correctamente. //Leer del archivo String str=(String)entrada. //Escribir en el archivo salida.println(ex).close().out. en este caso definidos en la clase Contacto. } catch (IOException ex) { System.writeObject(contacto).obj")).

en un contexto laboral. Si una clase tiene un método abstracto debe declararse abstracta. En Java el modificador abstract declara una clase abstracta: abstract class NombreClase {// …} Por ejemplo: public abstract class Persona { private String apellido. String c) {…} } Se crea una clase abstracta cuando se desea manipular un conjunto de clases a través de una interfaz común. // error: no se puede instanciar de clase // abstracta . una característica importante de estas clases es que de ellas no se pueden definir objetos. es decir. Clases abstractas e interfaces Clases abstractas Las clases abstractas representan conceptos generales.un formato propio de Java. public abstract class Metal {…} Metal mer=new Metal(). Unidad 4 parte4 Lenguaje de Programación Orientado a Objetos Unidad 4. // public void identificación (String a. y normalmente tienen métodos abstractos. engloban las características comunes de un conjunto de objetos. Persona. no se puede instanciar de una clase abstracta. La sintaxis para la declaración de un método abstracto es: abstract void f(). tienen sólo la declaración faltándoles el cuerpo del método. estos son métodos incompletos. el compilador devuelve un error siempre que se intenta crear un objeto de dichas clases. Las clases abstractas declaran métodos y atributos. es una clase abstracta que engloba las propiedades y métodos comunes a todo tipo de individuo que trabaja para una empresa. por ejemplo. por lo que no se pueden leer fácilmente con un simple editor de texto (ni editar).

Esto es útil cuando se desea una clase en la que no tiene sentido tener métodos abstractos. puesto que hacer una clase abstracta no fuerza a hacer abstractos todos sus métodos. Si no se hace así (y uno puede elegir no hacerlo) entonces la clase derivada también será abstracta y el compilador obligará a calificar esa clase con la palabra clave abstract. y se desea evitar que existan instancias de esa clase. Ejercicio: . Sólo serán abstractos algunos de sus métodos. Quedará del siguiente modo: Se puede ver que realmente no hay cambios más que en la clase base. Es posible crear una clase abstracta sin incluir ningún método abstracto en ella. La clase Instrumento puede convertirse fácilmente en una clase abstracta.Si se hereda de una clase abstracta y se desea hacer objetos del nuevo tipo. hay que proporcionar definiciones de métodos para todos los métodos que en la clase base eran abstractos.

Una clase derivada que no redefine un método abstracto es también abstracta. en consecuencia. Son abstractas y así se deben declarar si tienen al menos un método abstracto.1 Colecciones de tamaño flexible Cuando se escriben programas. Por ejemplo:   Las agendas electrónicas guardan notas sobre citas. éstas se diferencian en la forma de organizar los objetos y. frecuentemente se necesita agrupar los objetos en colecciones. Las bibliotecas registran detalles de los libros y las revistas que poseen. fechas de cumpleaños. etc. . en la manera de recuperarlos.8). for (int i=0. Ejemplo: Figura []af=new Figura [2].5. UNIDAD 5 PARTE 1 Lenguaje de Programación Orientado a Objetos Unidad 5. i<2. No se pueden crear objetos de ellas.10. } Normas de las clases abstractas:      Se declaran con la palabra reservada abstract como prefijo en la cabecera de la clase.Crear un arreglo de la clase abstracta Figura y crear objetos de las clases concretas Rectángulo y Círculo. reuniones.6). else af[i]=new Círculo(3. Colecciones Java proporciona un grupo de clases que almacenan secuencias de objetos de cualquier tipo: las colecciones. i++) { if (i%2==0) af[i]=new Rectángulo(4. Pueden tener atributos y métodos no abstractos. 5.

Una vez que se importa la clase ArrayList del paquete java.1 Abra el proyecto agenda1 en NetBeans y cree un objeto Agenda. el inventario cambia cuando se compran libros nuevos y cuando algunos libros viejos se archivan o se descartan. se puede usar ArrayList al principio de la definición de la clase Agenda para declarar el campo notas: private ArrayList<String> notas. Concepto Las colecciones de objetos son objetos que pueden almacenar un número arbitrario de otros objetos. Ejercicio 5. en una agenda electrónica se agregan nuevas notas para registrar eventos futuros y se borran aquellas notas de eventos pasados en la medida en que ya no son necesarios. Para poder agrupar un número arbitrario de elementos se puede definir una clase con una gran cantidad de campos individuales. Las colecciones pueden almacenar un número arbitrario de elementos en el que cada elemento es otro objeto. Las universidades mantienen registros de la historia académica de los estudiantes.util. Cuando use el método mostrarNota necesitará un parámetros con valor 0 (cero) para imprimir la primera nota. se deben especificar dos tipos: el tipo propio de la colección (en este caso ArrayList) y el tipo de los elementos que se planean almacenar en la colección (en . en una biblioteca. Aquí se ve una nueva construcción: la mención de String entre símbolos de menor (<) y de mayor (>): <String>. En la clase Agenda se utiliza la clase ArrayList que está definida en el paquete java. Por ejemplo.util. Almacene unas notas (que son simplemente cadenas) y luego verifique que el número que devuelve numeroDeNotas coincida con el número de notas que guardó. Una solución adecuada sería aquella que no requiera que conozcamos anticipadamente la cantidad de elementos que queremos agrupar o bien establecer un límite mayor que dicho número. La primera línea de la clase Agenda muestra el modo en que se obtiene el acceso a la clase ArrayList de la biblioteca de Java mediante la sentencia import: import java. Una característica típica de estas situaciones es que el número de elementos almacenados en la colección varía a lo largo del tiempo.util.ArrayList. Cuando se usan las colecciones. generalmente los programas necesitan una solución más general que la citada. de valor 1 para imprimir la segunda nota y así sucesivamente. Sin embargo. suficiente como para almacenar un número muy grande pero fijo de elementos. ArrayList es un ejemplo de una clase colección.

Los dos primeros se presentan en los métodos guardaNota y numeroDeNotas respectivamente.  Mantiene el orden de los elementos que se agregan. Compare la Figura 5. se crea un objeto de tipo ArrayList<String> y se guarda dentro del campo notas. El método add de un ArrayList almacena un objeto en la lista y el método size devuelve la cantidad de elementos que están almacenados realmente en ella. Su método size devuelve el número de objetos que contiene actualmente. Esto significa que  . es suficiente con apreciar lo útil que resulta su capacidad. En el constructor de la agenda. simplemente hace suficiente espacio para ellos. Todo el trabajo dificultoso lo hace el objeto ArrayList. La clase ArrayList declara muchos métodos. No es necesario preocuparse por cómo fue implementada la clase ArrayList para que tenga estas características. Se usa esta definición de tipo como el tipo de la variable notas. size y get. Existen por lo menos tres características importantes de una clase ArrayList que se deben observar: Es capaz de aumentar su capacidad interna tanto como se requiera: cuando se agregan más elementos.1 ilustra cómo se presentaría un objeto Agenda que contiene dos notas. Las clases similares a ArrayList que se parametrizan con un segundo tipo se denominan clases genéricas.este caso.2 en la que se almacenó una tercera nota. Se puede leer la definición completa del tipo como <<ArrayList de String>>. por lo que más tarde se pueden recuperar en el mismo orden. El objeto Agenda tiene un aspecto muy simple: tiene sólo un campo que almacena un objeto de tipo ArrayList<String>.1 con la Figura 5. en este ejemplo sólo se usan tres de ellos para implementar la funcionalidad que se requiere: add. seguido de los paréntesis para la lista de parámetros (vacía): notas=new ArrayList<String>().  Mantiene su propia cuenta privada de la cantidad de elementos que tiene actualmente almacenados. La Figura 5. String). 5. Se necesita especificar nuevamente el tipo completo con el tipo de elemento entre los símbolos de menor y de mayor. y esta es una de las grandes ventajas de usar clases de bibliotecas: alguien invirtió tiempo y esfuerzo para implementar algo útil y nosotros tenemos acceso prácticamente libre a esta funcionalidad usando esa clase.2 Estructuras de objetos con colecciones Para comprender como opera una colección de objetos tal como ArrayList resulta útil examinar un diagrama de objetos.

la agenda pasará la pregunta al objeto notas y luego devolverá cualquier respuesta que obtenga de él. Figura 5. la agenda delega la responsabilidad de mantener el número de elementos a su objeto ArrayList. Figura 5. A pesar de que la agenda tiene un método numeroDeNotas. La duplicación puede representar esfuerzos desperdiciados y puede generar inconsistencias cuando dos objetos que debieran brindar idéntica respuesta no lo hacen. En la segunda característica. En su lugar.se puede utilizar para escribir cualquier cantidad de clases diferentes que requieran almacenar un número arbitrario de objetos. . quiere decir que la agenda no duplica información que esté disponible desde cualquier otro objeto. esto tiene consecuencias importantes en el modo en que se implementa la clase Agenda.2 Una Agenda que contiene tres notas.1 Una Agenda que contiene dos notas. el objeto ArrayList mantiene su propia cuenta de la cantidad de objetos insertados. no se ha definido realmente un campo específico para guardar esta información. La duplicación de información o del comportamiento es algo sobre lo que se tiene que trabajar muy duro para evitarla. Si un usuario solicita información a la agenda sobre el número de notas que tiene guardadas.

parámetros y tipos de retorno.4 Numeración dentro de las colecciones En el proyecto agenda1 se observa que para imprimir las notas es necesario usar valores numéricos a partir de cero para el parámetro. un ArrayList de Rectángulos. Los elementos del ArrayList son de tipo Libro. y así sucesivamente. el segundo tiene al número 1. El primer elemento que se agrega a una colección tiene por índice al número 0. a diferencia de las clases no definen un tipo único en Java sino potencialmente muchos tipos. Los campos no pueden asignarse uno a otro. 5.3 Clases genéricas El tipo del campo notas fue declarado como: ArrayList<String> La clase se denomina ArrayList.2 Escriba la declaración de un campo privado de nombre biblioteca que pueda contener un ArrayList. Por lo tanto. Cada ArrayList en particular es un tipo distinto que puede usarse en declaraciones de campos. La razón de este requerimiento es que los elementos almacenados en las colecciones tienen una numeración implícita o posicionamiento que comienza a partir de cero. Por ejemplo. la clase ArrayList puede usarse para especificar un ArrayList de Strings. Estas declaraciones establecen que miembros contiene un ArrayList que puede almacenar objetos Persona. un ArrayList de Personas. El método mostrarNota del proyecto agenda1 ilustra la manera en que se usa un índice para obtener un elemento desde el ArrayList mediante su método get. se pueden definir los siguientes campos: private ArrayList<Persona> miembros. private ArrayList<MaquinaDeBoletos> misMaquinas. La Figura 4. Las clases que requieren este tipo de parámetro se denominan clases genéricas. ArrayList<Persona> y ArrayList<MaquinaDeBoletos> son tipos diferentes. o un ArrayList de cualquier otra clase que tengamos disponible. pero requiere que se especifique un segundo tipo como parámetro cuando se usa para declarar campos u otras variables. mientras que misMaquinas puede contener un ArrayList que almacena objetos MaquinaDeBoletos. La mayor parte del código . Por ejemplo. Las clases genéricas. La posición que ocupa un objeto en una colección es conocida como su índice.5. Ejercicio 5.3 ilustra la misma situación que antes. pero se muestran los números índice del objeto ArrayList. aun cuando sus tipos deriven de la misma clase.

aparece un mensaje que dice IndexOutBoundsException.3 Si una colección almacena 10 objetos. ¿qué valor devolverá una llamada a su método size? Ejercicio 5. public void eliminarNota(int numeroDeNota) { . Figura 5.1 muestra el método remove que se podría agregar a la clase Agenda. Ejercicio 5.4 Escriba una llamada al método get para devolver el quinto objeto almacenado en una colección de nombre elementos. hacer esto es fácil porque la clase ArrayList tiene un método remove que toma como parámetro el índice de la nota que será eliminada. En principio. 5..3 Índices de los elementos de una colección.6 Escriba una llamada para agregar el objeto contenido en la variable cita a una colección de nombre notas.del método mostrarNota es la concerniente a controlar que el valor del parámetro esté en el rango de valores válidos [0. Cuando un usuario quiera eliminar una nota de la agenda. El código 5. En Java. Ejercicio 5. se puede lograr con sólo invocar al método remove del objeto notas. Un error típico de programación es intentar acceder a un elemento de una colección que está fuera de los índices válidos del ArrayList.5 ¿Cuál es el índice del último elemento almacenado en una colección de 15 objetos? Ejercicio 5.5 Eliminar un elemento de una colección Sería muy útil tener la capacidad de eliminar las notas viejas de la Agenda cuando no nos interesen más. Es importante tener en cuenta que get no elimina un elemento de la colección. Cuando se hace esto. se obtiene un mensaje del error denominado desbordamiento.(size-1)] antes de llamar al método get.

el índice de la nota que originalmente tenía el número de índice 2 (“11:30 Ver a Juan”) ha cambiado al valor 1 mientras que la nota que tiene el índice 0 permanece sin cambios.7 Escriba una llamada a método para eliminar el tercer objeto almacenado en una colección de nombre notas. La Figura 5. la colección desplaza todos los siguientes elementos una posición a la izquierda para llenar el hueco. entonces no se hace nada. Los usuarios deben ser conscientes de estos cambios en los índices cuando agregan o eliminan notas. en consecuencia sus índices disminuyen en 1. Ejercicio 5.1 Eliminar una nota de la agenda Una complicación del proceso de eliminación es que se modifican los valores de los índices de las restantes notas que están almacenadas en la colección. y como resultado. Si se elimina una nota que tiene por índice un número muy bajo. } else { //No es un número de nota válido. Comenzando con la situación ilustrada en la Figura 5. se puede borrar notas. la nota número 1 (“Recargar teléfono”) ha sido eliminada. También es posible insertar elementos en un ArrayList en otros lugares distintos que el final de la colección.4 muestra la forma en que se modifican algunos índices de los elementos de un ArrayList debido a la eliminación de un elemento en medio de ella. .if(numeroDeNota<0) { //No es un número de nota válido.3.remove(numeroDeNota). Esto significa que los elementos que ya están en la lista deben incrementar sus índices cuando se agrega un nuevo elemento. } } Código 5. no se hace nada } else if(numeroDeNota<numeroDeNotas()) { //Número de nota válido.

System. pero el número de veces depende de circunstancias que pueden variar.9 Implemente un método eliminarNota en su agenda. Ejercicio 5. 4.println(notas.8 Suponga que un objeto está almacenado en una colección bajo el índice 6. System.6 Procesar una colección completa Si agregar y eliminar notas significa que los índices pueden cambiar con el tiempo. En el método listarTodasLasNotas se tiene la necesidad de hacer algo numerosas veces. Si hay tres notas se requieren tres sentencias println. Los métodos mostrarNota y eliminarNota ilustran que el rango de números de índice válidos en cualquier momento es *0…(size-1)]. si hay cuatro notas.out.out.get(0)). ¿Cuántas sentencias println requeriría la listarTodasLasNotas descrito en el ejercicio 5.pritnln(notas.11 Se sabe que la primera nota está almacenada en la posición 0 del ArrayList.11? versión completa del método Realmente no es posible responder esta pregunta porque depende de cuántas notas haya en la agenda en el momento en que sean listadas. 5. ¿Se puede escribir el cuerpo de ListarTodasLasNotas mediante las siguientes líneas? System.1 El ciclo for-each .6.get(1)). sería de gran ayuda tener un método en la clase Agenda que pueda listar todas las notas con sus índices actuales. y así sucesivamente. ¿Cuál será su índice inmediatamente después de que se eliminen los objetos de las posiciones 0 y 9? Ejercicio 5. Ejercicio 5.10 ¿Cómo debiera ser el encabezado del método listarTodasLasNotas? ¿Cuál debe ser su tipo de retorno? ¿Debe tener algún parámetro? Ejercicio 5. Esta clase de problemas se encuentra en muchos programas de diferente naturaleza y la mayoría de los lenguajes de programación tienen varias maneras de resolver tales problemas.out.4 Los índices se modifican después de la eliminación de un elemento. entonces se necesitan cuatro sentencias.Figura 5.pritnln(notas.get(2)). por lo que el método listarTodasLasNotas también debiera tener este tamaño dinámico en algún contador para poder imprimir todas las notas. La solución que se elige usar en esta etapa es el ciclo for-each. etc.

Se pueden resumir las acciones de un ciclo foreach en el siguiente pseudocódigo: for(TipoDeElemento elemento: colección) { Cuerpo del ciclo } Un ciclo for-each consta de dos partes: un encabezado de ciclo (la primera línea del ciclo) y un cuerpo a continuación del encabezado.println) se ejecuta rápidamente. tal como aparece en este pseudocódigo: Para cada elemento en la colección hacer: { cuerpo del ciclo } El código 5. luego el del índice 1.println(nota). cada elemento de la lista logra ser impreso. Por lo tanto. } } Código 5. antes de que la sentencia se ejecute. El cuerpo contiene aquellas sentencias que se desean llevar a cabo una y otra vez.2 Uso de un ciclo para imprimir las notas En este ciclo for-each. .out. En cada vuelta. una vez para cada elemento del ArrayList notas. sin tener que escribir esas acciones más de una vez. /** * Imprime todas las notas de la agenda */ public void imprimirNotas() { for(String nota: notas) { System. la variable notas se configura para contener uno de los elementos de la lista: primero el del índice 0. El ciclo for-each toma su nombre a partir de la manera en que se puede leer: si se lee la palabra clave for como <<para cada>> y los dos puntos en la cabecera del ciclo como las palabras <<en la>>. entonces la estructura del código anterior comienza a tener más sentido. la sentencia de impresión se ejecutaría cuatro veces. el cuerpo del ciclo (que consiste en una sola sentencia System.out. Por ejemplo: si en la lista de notas hubiera cuatro cadenas.2 muestra el método imprimirNotas.Un ciclo for-each es una forma de llevar a cabo repetidamente un conjunto de acciones. y así sucesivamente.

En lugar de recorrer todos los elementos de una colección. A esta variable se le llama variable de ciclo. que define una nueva variable local nota que se usará para contener los elementos de la lista. Sin embargo.13 Cree una Agenda y almacene algunas notas en ella. Algunas veces se necesita un poco más de control y Java ofrece una construcción de ciclo diferente que permite hacerlo: el ciclo while. no tiene porqué llamarse <<nota>>. La condición es una expresión lógica que se usa para determinar si el cuerpo debe ejecutarse por lo menos una vez. puede recorrer un número variable de elementos de la colección. en este caso String. Este es un gran paso. Este ciclo es más flexible que el ciclo for-each. Cada vez que . los detalles son diferentes. Cada elemento de esta colección será asignado en su turno a la variable de ciclo. Está seguida por un par de paréntesis en los que se definen los detalles del ciclo. dependiendo de la condición del ciclo. pero no resuelve todos los problemas. Utilice el método imprimirNotas para mostrarlas por pantalla y verificar que el método funciona como debiera. y el cuerpo puede ejecutarse repetidamente. Ejercicio 5. Ya se ha visto cómo se puede usar el ciclo for-each para llevar a cabo algunas operaciones (el cuerpo del ciclo) sobre cada elemento de una colección. Si la condición se evalúa verdadera. A continuación aparecen dos puntos y la variable que contiene la colección que se desea procesar. se ejecuta el cuerpo del ciclo. Ejercicio 5. seguida de una condición. Aquí está la estructura de un ciclo while: while (condición del ciclo) { cuerpo del ciclo } Se puede ver que el ciclo while comienza con la palabra clave while. Luego se puede usar en el cuerpo del ciclo la variable de ciclo para hacer referencia a cada elemento.14 Modifique los métodos mostrarNota y eliminarNota para que impriman un mensaje de error si el número ingresado no fuera válido.2 El ciclo while Un ciclo while es similar en su estructura y propósito que el ciclo for-each: consiste en un encabezado de ciclo y un cuerpo. y para cada una de estas asignaciones el cuerpo del ciclo se ejecutará una sola vez. El primero de esos detalles es la declaración String nota. El tipo de la variable del ciclo debe ser el mismo que el tipo del elemento declarado para la colección que se está usando. Se puede elegir el nombre de esta variable de la misma manera que el de cualquier otra variable. Ejercicio 5.12 Implemente el método imprimirNotas en el proyecto agenda1.6. UNIDAD 5 PARTE 2 5.En el ciclo for each la palabra clave for introduce el ciclo.

tal como se ha hecho anteriormente mediante un ciclo for-each.get(indice)). Son relevantes algunas observaciones: En este ejemplo. Si se nos olvida incrementar la variable índice (la última línea del cuerpo del ciclo) la condición del ciclo nunca podría ser evaluada como falsa y el ciclo se repetiría indefinidamente. En la versión del ciclo while es posible cometer errores que den por resultado un ciclo infinito. En realidad el programa está haciendo mucho: ejecuta un ciclo una y otra vez. indice++. Los elementos de la lista no son extraídos automáticamente de la colección y asignados a una variable. Se tiene que declarar fuera del ciclo una variable para el índice e iniciarlo en 0 para acceder al primer elemento de la lista.println(notas. si el ciclo no contiene una sentencia de corte. Este proceso continua repetidamente hasta que la condición resulta falsa. En cambio. Se debe recordar incrementar la variable contadora (índice). el programa aparecerá como <<colgado>>: parece que no está haciendo nada y no responde a ningún clic del ratón o a pulsar una tecla.3 Uso de un ciclo while para mostrar todas las notas.out. pero no podemos ver ningún efecto de esto y parece que el programa hubiera muerto. esto se tiene que hacer usando el método get del ArrayList. el ciclo for-each es claramente bueno para nuestro objetivo. el ciclo while resulta un poco más complicado. } Código 5. ¿cuáles son los beneficios de usar un ciclo while en lugar de un ciclo for-each? . Hasta ahora.se ejecuta el cuerpo del ciclo. la condición se vuelve a controlar nuevamente. Este es un error típico de programación y hace que el programa continúe ejecutándose eternamente. fue menos complicado de escribir y es más seguro porque garantiza que siempre llegará a un final.size()) { System. Se puede escribir un ciclo while que imprima todas las notas de la lista.3 int indice=0. que es el punto en el que se salta del cuerpo del ciclo y la ejecución continúa con la sentencia que esté ubicada inmediatamente después del cuerpo. La versión que usa un ciclo while se muestra en el código 5. Este ciclo while es equivalente al ciclo for-each que se ha discutido en la sección anterior. También se tiene que llevar la cuenta (índice) para recordar la posición del ArrayList. En tal situación. while (indice<notas. Por lo tanto.

. El código que se muestra en el ejemplo anterior es parte de este método. se requiere un método de nombre buscar que tenga un parámetro String de nombre cadABuscar y luego imprima en pantalla la primer nota de la agenda que contenga la cadena de búsqueda.println(numero). if (nota. El siguiente ciclo imprime en la pantalla todos los números pares hasta 30. en segundo lugar.contains(cadABuscar)) { encontrado=true. while (numero<=30) { System. int numero=0. Necesita agregar código a continuación del ciclo para mostrar si se encontró la nota o bien la cadena <<No se encontró el elemento buscado>>. } Ahora se puede usar el ciclo while para escribir un ciclo que busque en la colección un elemento específico y se detenga cuando lo encuentre. boolean encontrado=false.15 Implemente el método buscar en la clase Agenda tal como se describió anteriormente. Para ser precisos. no se necesita procesar cada uno de sus elementos. Asegúrese de probar su método dos veces como mínimo. } else { indice++.size() && !encontrado) { String nota=notas. while (indice<notas.get(indice). numero=numero+2. en cambio. } } Como puede verse en este código la condición está escrita de tal manera que el ciclo se detiene bajo cualquiera de estas dos condiciones: si efectivamente se encuentra la cadena buscada. aún si se usara el ciclo para procesar la colección. buscando una cadena que sabe está en la lista y una que sabe que no está. el ciclo while no necesita estar relacionado con una colección. Se puede llevar a cabo esta tarea con la siguiente combinación del ciclo while con una sentencia condicional: int indice=0. pero no está completo. Este es un ejemplo simple de un ciclo while que no está relacionado con una colección.out. Ejercicio 5.Existen dos fundamentos: primeramente. o cuando se han controlado todos los elementos y no se encontró la cadena buscada. se podría frenar el recorrido tempranamente.

Concepto Un iterador es un objeto que proporciona funcionalidad para recorrer todos los elementos de una colección.ArrayList. Por ejemplo: 0: Comprar pan. Ejercicio 5. se le pregunta repetidamente a la colección notas cuántas notas contiene actualmente. 5. ¿Varía el valor que retorna size en cada verificación? Si considera que la respuesta es no.util de modo que se debe agregar una segunda sentencia import a la clase Agenda para poder usarla. pero usted puede presentar las notas numeradas a partir de 1 en su listado. Esta variante utiliza un ciclo while para llevar a cabo el recorrido y un objeto iterador en lugar de una variable entera como índice del ciclo para mantener el rastro de la posición en la lista. se discutirá una tercer variante para recorrer una colección. Ejercicio 5. Se lleva a cabo cada vez que se evalúa la condición del ciclo. El método iterator de ArrayList devuelve un objeto Iterator. Asegúrese de modificar adecuadamente los métodos mostrarNota y eliminarNota. A continuación se describe en pseudocódigo la manera en que se usa generalmente un Iterator: . antes de la ejecución del ciclo.6.3 Recorrer una colección Antes de avanzar. Recuerde que el objeto ArrayList continuará usando el índice a partir de cero. Luego utilice la variable local en la condición del ciclo en lugar de una invocación a size.17 En una ejecución del método buscar. La clase Iterator también está definida en el paquete java.18 Modifique su agenda de modo que las notas se numeren a partir de 1 y no de 0.Ejercicio 5. import java. escriba el método buscar de modo que el tamaño de la colección notas se determine una única vez y se almacene en una variable local.Iterator. import java. Pruebe que esta versión produce el mismo resultado que la versión anterior.util. Examinar cada elemento de una colección es una actividad tan común que un ArrayList proporciona una forma especial de recorrer o iterar su contenido. 1: Regargar teléfono 2: 11:30 Ver a Juan Este listado hace que sea mucho más fácil ingresar el índice correcto en el momento de eliminar una nota de la agenda. Un Iterator prove dos métodos para recorrer una colección: hasNext y next.util.16 Modifique el método imprimirNotas de modo que muestre al comienzo de cada nota un número que corresponda a su índice en el ArrayList.

7 Resumen del ejemplo agenda En el ejemplo agenda se vio cómo se puede usar un objeto ArrayList para almacenar un número arbitrario de objetos en una colección. En esta última versión se usa explícitamente un ciclo while.iterator().println(it. El iterador comienza en el inicio de la colección y trabaja progresivamente. Se puede escribir un método que usa un iterador para listar por pantalla todas las notas. de a un objeto a la vez.out. las dos que se han usado son el ciclo for-each y el ciclo while.4 Uso de un Iterator para recorrer la lista de notas. se parametriza con el tipo de los elementos de la colección.next()). Luego se usa dicho iterador para controlar repetidamente si hay más elementos (it. tal como se muestra en el Código 5. } } Código 5. . Java tiene varias construcciones para ciclos.4. /* * Listar todas las notas de la agenda */ public void listarTodasLasNotas() { Iterator<String> it=notas. Porque el Iterator sabe si quedan más elementos en la lista (hasNext) y cuál es el que debe retornar (next).iterator(). Como se puede ver Iterator también es tipo genérico y por lo tanto. 5. while (it.Iterator<TipoDeElemento> it=miColeccion. Se explicó cómo se puede usar un ciclo para recorrer todos los elementos de una colección.hasNext()) { System. while (it.hasNext()) { Invocar it. si es que hay alguno.next() para obtener el siguiente elemento Hacer algo con dicho elemento } En este fragmento de código se usa primero el método iterator de la clase ArrayList para obtener un objeto iterador.hasNext()) y para obtener el siguiente elemento (it. No se tiene que decidir anticipadamente cuántos objetos se desea almacenar y el objeto ArrayList mantiene automáticamente el registro de la cantidad de elementos que contiene. Un punto a destacar es que se le pide al iterador que devuelva el siguiente elemento y no a la colección. pero no es necesario tomar precauciones respecto a la variable índice. cada vez que se invoca su método next.next()).

se tiene la opción de elegir usar una colección de objetos de tamaño fijo. Sin embargo. Tal como el ArrayList. Otros ejemplos de colecciones de tamaño flexible son Vector.8 Colecciones de tamaño fijo Las colecciones de tamaño flexible son muy potentes porque no es necesario conocer anticipadamente la cantidad de elementos que contienen. Una colección de tamaño fijo se denomina array o arreglo. Un mapa es una colección de pares de objetos llave/valor. al ingresar un elemento por segunda vez simplemente no tiene ningún efecto. especializada para almacenar los elementos. . Vector es igual a ArrayList.  Los arreglos son capaces de almacenar objetos o valores de tipos primitivos.En un ArrayList se puede acceder a sus elementos por un índice o se puede recorrer el ArrayList completamente usando un objeto Iterator. Las colecciones de tamaño flexible sólo pueden almacenar objetos. Las diferencias reales residen en el comportamiento de cada colección. se pueden usar todas. Concepto Un arreglo es un tipo especial de colección que puede almacenar un número fijo de elementos. En tales circunstancias. 5. algunas aplicaciones son diferentes por el hecho de que se conoce anticipadamente cuántos elementos se desean almacenar en la colección y este número permanece invariable durante la vida de la colección. Por otro lado un conjunto no mantiene un orden específico (el iterador puede devolver los elementos en diferente orden del que fueron ingresados) y asegura que cada elemento en el conjunto esté una única vez. En vez de buscar las entradas en esta colección mediante un índice entero (como se hace con el ArrayList) se usa el objeto llave para buscar el objeto valor. Los diferentes tipos de colecciones de Java se usan de manera muy similar. En un conjunto. en un Map cada entrada no es un único objeto sino un par de objetos. provee acceso a sus elementos a través de un índice y puede contener el mismo elemento varias veces. sólo que Vector ya es una colección obsoleta. Una diferencia entre el ArrayList y un Map es que. A pesar del hecho de que los arreglos tengan un tamaño fijo puede ser una desventaja. con respecto a las clases de colecciones de tamaño flexible:  El acceso a los elementos de un arreglo es generalmente más eficiente que el acceso a los elementos de una colección de tamaño flexible. un mapa puede almacenar un número flexible de entradas. se obtienen por lo menos dos ventajas en compensación. Este par está compuesto por un objeto llave y un objeto valor. Por ejemplo. una lista contiene todos los elementos ingresados en el orden deseado. Ya vimos los conjuntos (HashSet) y los mapas (HashMap) en la unidad 2. Una vez que se comprende cómo usar una de ellas. Set y Map.

30 */ public class AnalizadorLog { // Arreglo para almacenar la cantidad de accesos por hora. Barnes and Michael Kolling. Dadas las herramientas convenientes. estos archivos de registro permiten a los administradores de servicios web extraer y analizar información útil tal como:    Cuáles son las páginas web más populares que proveen. . Cada línea registra la fecha y hora del acceso en el siguiente formato: año mes día hora minutos Por ejemplo. Esta información puede permitir a los administradores.03. por ejemplo.5) Código 5. La cantidad de datos entregada a los clientes. Los períodos de mayor cantidad de accesos durante un día. // Usa un LectorDeArchivoLog para acceder a los datos. private int[] contadoresPorHora.8. El proyecto analizador-weblog contiene una aplicación que lleva a cabo un análisis de los datos de un servidor web.UNIDAD 5 PARTE 3 5. En la clase LogAnalyzer se pueden ver ejemplos de creación y uso de un arreglo (Código 5. En la carpeta del proyecto hay un ejemplo de un archivo de registro denominado weblog. determinar si necesitan actualizar sus servidores para que resulten más potentes o establecer los períodos de menor actividad para realizar las tareas de mantenimiento. El servidor graba una línea de registro en un archivo cada vez que se realiza un acceso.txt. * @version 2006. típicamente mantienen archivos de registro de los accesos de los clientes a las páginas web que almacenan. EntradaDeLog y SeparadorDeLineaLog. * * @author David J.1 Un analizador de un archivo de registro o archivo log Los servidores web.5 El analizador de archivo log /** * Lee los datos de un servidor web y analiza * los modelos de acceso de cada hora. una semana o un mes. private LectorDeArchivoLog lector. LectorDeArchivoLog. la línea siguiente registra un acceso hecho a las 3:45 am del 7 de junio de 2006: 2006 06 07 03 45 El proyecto consta de cuatro clases: AnalizadorLog.

hayMasDatos()) { EntradaDeLog entrada = lector.getHora().out. } } .out. contadoresPorHora[hora]++. lector = new LectorDeArchivoLog(). // Crea el lector para obtener los datos. } } /** * Imprime las líneas de datos leídas por el * LectorDeArchivoLog */ public void imprimirDatos() { lector.println("Hora: Cantidad"). int hora = entrada.siguienteEntrada(). * Debe ser rellenado previamente mediante un * llamado a analizarPorHora */ public void imprimirContadoresPorHora() { System.imprimirDatos(). } } /** * Imprime las cantidades de accesos hora por hora. hora++) { System. hora < contadoresPorHora.println(hora + ": " + contadoresPorHora[hora])./** * Crea un objeto para analizar los accesos a la web en cada * hora. */ public AnalizadorLog() { // Crea un objeto arreglo para guardar la cantidad // de accesos por hora.length. */ public void analizarPorHora() { while(lector. } /** * Analiza los accesos por hora a partir de los * datos del archivo log. for(int hora = 0. contadoresPorHora= new int[24].

sólo reserva un espacio de memoria para que en un próximo paso. Proporciona información que podría permitir determinar en qué horas del día el servidor tiende. La declaración de una variable arreglo no crea en sí misma un objeto arreglo. una vez que dicho objeto se hay creado.5 muestra el resultado de esta asignación. Se dice que int es el tipo base de este arreglo en particular. durante el periodo cubierto por el archivo log.20 Escriba una declaración de una variable arreglo de nombre gente que podría usarse para referenciar un arreglo de objetos Persona. A continuación llame al método imprimirContadoresPorHora.3 Creación de objetos arreglo El constructor de la clase AnalizadorLog incluye una sentencia para crear un arreglo de enteros: contadoresPorHora=new int[24]. Es importante distinguir entre una declaración de una variable arreglo y una declaración simple ya que son bastante similares: int hora. ¿Qué resultados muestra el analizador? ¿Cuáles son las horas del día en que se realizaron más accesos? 5. se cree el arreglo. en promedio. Ejercicio 5. Este detalle indica que la variable contadoresPorHora es de tipo arreglo de enteros. La característica distintiva de la declaración de una variable de tipo arreglo es un par de corchetes que forman parte del nombre del tipo: int[ ]. Ejercicio 5. boolean[5000] ocupado.8.8. Esta sentencia crea un objeto arreglo que es capaz de almacenar 24 valores enteros y hace que la variable arreglo contadoresPorHora haga referencia a dicho objeto.El analizador utiliza realmente solo una parte de los datos almacenados en una línea de un archivo log de un servidor.21 Encuentre los errores de las siguientes declaraciones y corríjalas. Ejercicio 5. En este caso. int[ ] contadoresPorHora. la variable hora es capaz de almacenar un solo valor entero mientras que la variable contadoresPorHora se usará para hacer referencia a un objeto arreglo. usando el operador new. a estar más ocupado o desocupado y lo hace contando la cantidad de accesos que se realizaron en cada hora. La figura 5. [ ] contadores. . 5. Para ello cree un objeto AnalizadorLog e invoque su método analizarPorHora.19 Explore el proyecto weblog-analyzer.2 Declaración de variables arreglos La clase AnalizadorLog contiene un campo que es de tipo arreglo: private int[ ] contadoresPorHora.

Es importante observar que la creación del arreglo asignado a nombres no crea realmente 10 cadenas. Cuando se asigna un objeto arreglo a una variable arreglo. Escriba sentencias que lleven a cabo las siguientes tareas: a) la variable lecturas hace referencia a un arreglo capaz de contener 60 valores de tipo double. La asignación a contadoresPorHora es una variable arreglo de enteros. c) la variable maquinas hace referencia a un arreglo capaz de contener cinco objetos MaquinaDeBoletos. double [ ] precios= new double(50). Ejercicio 5. es decir. En realidad. b) la variable urls hace referencia a un arreglo capaz de contener 90 objetos String. .24 Detecte el error que presenta la siguiente declaración de arreglo y corríjalo. un número fijo de elementos a almacenar. String [ ] urls. La expresión entera especifica el tamaño del arreglo. Ejercicio 5. Ejercicio 5. crea una colección de tamaño fijo que es capaz de almacenar 10 cadenas en ella.Figura 5.23 ¿Cuántos objetos String se crean mediante la siguiente declaración? String [ ] etiquetas=new String[20].22 Dadas las siguientes declaraciones de variables: double [ ] lecturas. MaquinaDeBoletos [ ] maquinas.5 Un arreglo de 24 enteros La forma general de la construcción de un objeto arreglo es: new tipo[expresión-entera] La elección del tipo especifica de qué tipo serán todos los elementos que se almacenarán en el arreglo. La línea siguiente declara una variable arreglo de cadenas que hace referencia a un arreglo que tiene capacidad para 10 cadenas: String [ ] nombres=new String[10]. el tipo del objeto arreglo debe coincidir con la declaración del tipo de la variable.

en ambos lados de una asignación. La tarea de la clase LectorDeArchivoLog es tomar cada línea del archivo de registros y separar los valores de los datos. por ejemplo. maquinas[0].getHora(). Las expresiones que seleccionan un elemento de un arreglo se pueden usar en cualquier lugar que requiera un valor de tipo base del arreglo.getNombre()). 5. Los índices de los arreglos siempre comienzan por cero y van hasta el valor uno menos que la longitud del arreglo.println(gente[3]. Estos son algunos ejemplos de uso de expresiones con arreglos en diferentes lugares: etiqueta[5]=”Salir”. El uso de un índice de un arreglo en el lado izquierdo de una asignación es equivalente a un método de modificación (o método set) del arreglo porque cambiará el contenido del mismo. Esto quiere decir que se pueden usar.4 Usar objetos arreglo Se accede a los elementos individuales de un objeto arreglo mediante un índice. Estos dos métodos imitan el estilo de los métodos hasNext y next de la clase Iterator dado que puede haber un número arbitrario de entradas en un archivo log particular. . Los datos se almacenan en el arreglo dentro del método analizarPorHora y los datos del arreglo se muestran en el método imprimirContadoresPorHora. El analizador delega la tarea de leer el archivo a la clase LectorDeArchivoLog.5 Analizar el archivo log El arreglo contadoresPorHora creado en el constructor de AnalizadorLog se usa para almacenar un análisis de los datos sobre el acceso.out. maquinas[0]=new MaquinaDeBoletos(500).8. Para cada EntradaLog. Por ejemplo: etiquetas[6]. Por lo que los índices válidos para el arreglo contadoresPorHora son de 0 hasta 23. double mitad=lecturas[0]/2. Como la tarea del método analizar es contar cuantos accesos se hicieron durante cada período de una hora del día. el método analizarPorHora del analizador obtiene el valor del campo hora: int hora=entrada. Un índice es una expresión entera escrita entre un par de corchetes a continuación del nombre de una variable arreglo.8. Los restantes usos del índice son equivalentes a los métodos de acceso (o métodos get). Los valores válidos para una expresión que funciona como índice dependen de la longitud del arreglo en el que se usarán. gente[x+10-y].5. System. este tiene dos métodos: public boolean hayMasDatos() public boolean siguienteEntrada() El método hayMasDatos le dice al analizador si existe por lo menos una entrada más en el archivo de registros y el método siguienteEntrada retorna un objeto EntradaLog que contiene los valores de la siguiente línea del archivo.

} El resultado de este ciclo será que el valor de cada elemento del arreglo se imprime en pantalla precedido por su correspondiente número de hora. en cada iteración. hora++) { System. La segunda variante es el ciclo for. pues se usa un elemento de un arreglo exactamente de la misma forma en que se puede hacer con una variable común: contadoresPorHora[hora]=contadoresPorHora[hora]+1. de la siguiente manera: contadoresPorHora[hora]++. el cual es una estructura de control repetitiva alternativa que resulta particularmente útil cuando:  Se quiere ejecutar un conjunto de sentencias un número exacto de veces. es común el uso del ciclo for cuando se quiere hacer algo con cada elemento de un arreglo tal como imprimir el contenido de cada elemento. acción modificadora) { sentencias a repetir } El siguiente ejemplo concreto está tomado del método imprimirContadoresPorHora del analizador del archivo log: for(int hora=0.println(hora+": " +contadoresPorHora[hora]). cada vez que se lee un valor de hora se actualiza el contador de esa hora en 1. Un ciclo for tiene la siguiente forma general: for(inicialización. generalmente en 1.6 El ciclo for Java tiene dos variantes para el ciclo for. La primer variante es el ciclo for-each. 5.8.length. Por ejemplo. el cual es una manera conveniente de recorrer una colección flexible. hora<contadoresPorHora. condición. De modo que. Al final del método analizarPorHora se tiene un conjunto completo de valores en los contadores para cada hora del período del archivo de registros. contadoresPorHora[hora]+=1.  Se necesita una variable dentro del ciclo cuyo valor cambie en una cantidad fija.Se sabe que el valor almacenado en la variable local hora se mantendrá siempre en el rango 0 a 23 que coincide exactamente con los valores del rango de los índices del arreglo contadoresPorHora.out. Cada posición del arreglo se usa para representar un contador de accesos para la hora correspondiente. Las siguientes alternativas son equivalentes a esta. Por ejemplo: 0: 149 1: 149 2: 148 … 23: 166 .

 La condición usa el operador menor que < para controlar el valor de hora respecto de la longitud del arreglo. Esto ocurre porque el ciclo for-each no proporciona acceso a la variable contadora del ciclo.length) { System. cuando se desea acceder a cada elemento de un arreglo.println(hora + ": " + contadoresPorHora[hora]). El valor de este campo coincide siempre con el valor entero usado para crear el objeto arreglo. } En estas dos versiones se puede ver que la acción modificadora no se ejecuta realmente hasta que no se hayan ejecutado las sentencias del cuerpo del ciclo. por este motivo aparece como la última sección en el encabezado del ciclo for.out.Se puede ilustrar la forma en que se ejecuta un ciclo for reescribiendo su forma general mediante un ciclo while equivalente: inicialización. que se necesita en este caso para imprimir la hora. indice++) Esto es correcto porque no se quiere usar un valor para el índice igual a la longitud del arreglo pues tal elemento no existe nunca.length. Aquí hay un intento: for(int valor: contadoresPorHora) { System. inmediatamente antes de evaluar la condición por primera vez. índice<arreglo. se tiene un problema: no se puede imprimir fácilmente la hora antes de los dos puntos.out. En general. usarse con ciclos for-each tal como se hizo con las otras colecciones. Además. de hecho. ¿Se puede rescribir también el ciclo for mostrado anteriormente mediante un ciclo for-each? La respuesta es: casi siempre. se puede ver que la inicialización se ejecuta una sola vez. while (hora<contadoresPorHora. el encabezado del ciclo tendrá la siguiente forma: for (int indice=0. } En este fragmento de código se puede ver que los arreglos pueden. el valor de length será 24. el ciclo continuará siempre que la hora sea menor de 24. Por lo que. Por lo que en este caso.length Esto ilustra dos puntos importantes:  Todos los arreglos contienen un campo length que contiene el valor del tamaño del arreglo. .println(": "+ valor). while (condición) { sentencias a repetir condición modificadora } Por lo que la alternativa del cuerpo de imprimirContadoresPorHora sería: int hora=0. Sin embargo. hora++. En ambas versiones aparece la condición hora<contadoresPorHora.

out. * @param marcas Un arreglo que contiene valores de marcas * @param promedio El promedio de las marcas */ public void imprimirMayores (double marcas. Ejercicio 5. Ejercicio 5. Complételo usando un ciclo for para recorrer contadoresPorHora.28 Complete el método númeroDeAccesos que se da a continuación para contar el total de accesos grabados en el archivo de registros. double promedio) { for(indice=0. indice++) { if (marcas[indice]>promedio) { System. //sumar el valor de cada elemento de contadoresPorHora a total .length. } .26 Reescriba el cuerpo de imprimirContadoresPorHora de modo que reemplace al ciclo for por un ciclo while equivalente.25 Verifique que ocurre si en la condición del ciclo for se usa incorrectamente el operador <= en el método imprimirContadoresPorHora: for (int hora=0.Para arreglar este código es necesario definir una propia variable contadora (de manera similar al ejemplo con el ciclo while).27 Corrija todos los errores que encuentre en el siguiente método /* * Imprime todos los valores del arreglo marcas * que son mayores que el promedio. /* * Devuelve el número de accesos grabados en el archivo log */ public int numeroDeAccesos() { int total=0. indice<=marcas. } } } Ejercicio 5. Invoque el método reescrito para comprobar que imprime los mismos resultados que antes.length. hora<=contadoresPorHora. return total. En lugar de esto.. hora++) Ejercicio 5. se prefiere usar el ciclo for ya que es más conciso.println(marcas[indice])..

Clases genéricas Uno de los objetivos clave en el mundo de la programación es diseñar clases y métodos que actúen sobre tipos arbitrarios o genéricos. Use un ciclo for o un ciclo for-each. una vez que la clase genérica se ha definido.30 Agregue un método horaMasTranquila al AnalizadorLog que devuelva el número de la hora con menos cantidad de accesos. la clase genérica Pila puede describir una pila de objetos arbitrarios. Las clases genéricas son útiles para diseñar clases contenedoras que engloben objetos de algún otro tipo. arreglos. conjuntos. sin embargo. por ejemplo: un algoritmo que implementa una pila de caracteres es esencialmente igual al que es necesario para implementar una pila de enteros.31 ¿Qué hora regresa el método horaMasOcupada si existe más de una hora con el mismo nivel de accesos? UNIDAD 6 PARTE 1 6. los usuarios pueden escribir el código que utiliza pilas de tipos de datos reales. ya que sirve principalmente para aumentar la reutilización.1 Genericidad La genericidad es una construcción importante en un lenguaje de programación orientada a objetos. todas ellas se definen con independencia del tipo de los objetos . La genericidad es una propiedad que permite definir una clase o un método sin especificar el tipo de datos o parámetros de uno o más de sus miembros. en Java existen las plantillas que permiten definir clases genéricas o paramétricas que implementan esas estructuras o clases con independencia del tipo de elemento que procesan. cadenas. por ejemplo. La razón de la genericidad se basa principalmente en el hecho de que los algoritmos de resolución de numerosos problemas no dependen del tipo de datos que procesan. listas. serán instanciadas para producir paquetes o clases reales que ya utilizan tipos de datos concretos. Se puede llevar a cabo esta tarea recorriendo el arreglo contadoresPorHora para encontrar el elemento que contiene el mayor número. algunos ejemplos típicos de estas son pilas. para definir clases y métodos genéricos se definen los tipos parametrizados o tipos genéricos. colas. diccionarios.29 Agregue un método horaMasOcupada al AnalizadorLog que devuelva la hora de mayor cantidad de accesos del día. las plantillas o clases genéricas tras ser implementadas. etcétera. etc. Los tipos parametrizados o genéricos se pueden utilizar para implementar estructuras y algoritmos independientes del tipo de objetos sobre los que operan. Ejercicio 5. reales o cadenas. la genericidad es beneficiosa. de esta forma se puede cambiar la clase para adaptarla a diferentes usos sin tener que reescribirla. ¿Qué ciclo resulta mejor para este caso? Ejercicio 5.Ejercicio 5. 6. ya que permite escribir un código más seguro y fácil de leer.

listas.contenidos y es el usuario de la clase quien deberá especificar el tipo de argumento de la clase en el momento que se instancia. matrices. … } La clase Punto es genérica. los contenedores manejan estructuras de datos . por ejemplo: class Punto <T> { private T x. por ejemplo. etc. el tipo parametrizado genérico. clases que contienen objetos de un tipo de dato.2 Declaración de una clase genérica Las plantillas de clase permiten definir las clases genéricas que pueden manipular diferentes tipos de datos. grafos y cualquier otra estructura de datos de propósito general. una aplicación importante es la implementación de contenedores. después del nombre de la clase. es posible utilizar una clase plantilla para crear una pila genérica que se puede instanciar para diversos tipos de datos predefinidos y definidos por el usuario.U> {…} Las variables tipo se utilizan en la definición de la clase para especificar los tipos retorno que devuelven los métodos. . encerrada entre corchetes tipo ángulo. vectores. definida con independencia del tipo de dato. también puede tener clases plantillas para colas. listas. el ámbito del argumento genérico es toda la clase. private T y. la cual representa cualquier agrupación de tres elementos. la clase Punto introduce una variable tipo T. 6. árboles. T (variable tipo). el cual se limita a clases o tipos de datos predefinidos por el usuario. Una clase genérica puede tener más de una variable tipo. En terminología orientada a objetos. tablas. por ejemplo: private T primero. Una clase genérica (parametrizable) es una clase con una o más variables tipo. conjuntos. las plantillas de clases también se denominan clases parametrizables. // uso de variables tipo Ejemplo 6.1 Declarar la clase genérica Terna. tales como vectores (arreglos). en esencia. la sintaxis de la plantilla de clase genérica es: class NombreClase <nombre_tipo> {…} donde NombreClase es el nombre de la clase genérica y nombre_tipo.. los tipos de campos y las variables locales. por ejemplo: al definir la clase Punto con tipos independientes para el primero y segundo campos: public class Punto <T.

else if (i==2) p2=valor. else if (i==2) return p2.p3=p3. que se puede utilizar como si fuera un tipo de clase en todo el ámbito de la clase. this.p2=p2. private T p3. else return p3."+ p2+ ". class Terna <T>{ private T p1. } public String toString() { return "Terna: " +p1+"."+p3. if (i==1) p1=valor. T p2. int i) throws Exception { if (!(i>=1 && i<=3)) throw new Exception("Violación de Terna"). if (i==1) return p1.La clase tiene el argumento genérico T. null). public Terna() { //p1=p2=p3=null. this(null. } . private T p2.p1=p1. this. null. } public T get(int i) throws Exception { if (!(i>=1 && i<=3)) throw new Exception("Elemento no existe"). else if (i==3) p3=valor. } public Terna(T p1. } public void set(T valor. T p3) { this.

éstos se colocan entre corchetes angulares separados por comas. puede haber tantos parámetros genéricos como sea necesario. Integer p1. posicion=0. esto equivale a declarar una clase ordinaria Terna de tres elementos cuyo tipo es Integer. U inx) { datos[posicion]=elem. index[posicion++]=inx. } T getDato() { int p=posicion. return index[--p]. private int posicion. } void set (T elem. } U getIndex() { int p=posicion. return datos[--p]. por ejemplo. .3 Objetos de una clase genérica Para utilizar la plantilla de la clase genérica se debe proporcionar un argumento para cada parámetro de la plantilla: Terna<Integer> pt.} Una clase genérica no se limita a un parámetro genérico. public Mapa(int n) { datos=(T[]) new Object[n].U> { private T[] datos. } } UNIDAD 6 PARTE 2 6. private U[] index. index=(U[]) new Object[n]. Se sustituyó el tipo genérico T por el tipo concreto Integer. la siguiente especificación de la clase plantilla Mapa con dos parámetros genéricos: class Mapa <T.

p3). System. } catch (Exception e) { System.2 Escribir un programa que permita crear dos objetos Terna y realizar operaciones con ellos. Terna<Double> pd=new Terna<Double>(d1.set(34.5.set(21.out.out. public class usaTerna { public static void main(String[] a) { try{ Terna<Integer> tc=new Terna<Integer>().out. Declarar una terna de números complejos: Terna<Complex> pz. pz=new Terna<Complex>. System. -2. También se puede hacer con una sentencia: Terna<Integer> pt=new Terna<Integer>(p1. tc. Integer p3.1).d2.3). p2. Para crear objetos de tipo Terna se sustituye el argumento genérico por el tipo concreto: pt=new Terna<Integer>.d3).print(e).set(323. con los métodos: Integer get(int i) void set(Integer p1. equivale a declarar una clase Terna de elementos cuyo tipo es Complex. tc. Terna<Double> td=new Terna<Double>(1. } . 12. tc. Integer p3).println(tc).println(td).Integer p2. Integer p2. Ejemplo 6.2).5.5).

por ejemplo: no es válido Mapa<String. } } } Para crear objetos tipo Mapa. una clase plantilla se puede instanciar con cualquier tipo de dato clase.Integer>(). por ejemplo: no es válido el siguiente código: public Ejemplar<T> { private T dato. Integer index[]. y el método: void set(String elem.out.3. arreglo de tipo genérico. por ejemplo: no es correcto T[] matriz=new T[10]. lo que equivale a declarar la clase ordinaria Mapa con dos elementos de tipo: String datos[]. No se pueden crear objetos del tipo genérico. public Ejemplar() { dato=new T().getTime()). //error } … 3. No se puede instanciar una clase genérica con tipos de datos primitivos. tampoco Terna<char> tc. fecha:"+ new GregorianCalendar(). 1. No se pueden crear arreglos de tipo genérico. por ejemplo: de la clase Terna se crearon objetos de tipo Double o Complex.finally { System. con dos argumentos genéricos. Esta restricción no impide declarar un argumento.int> mp. 2. se sustituye cada uno por el tipo concreto: Mapa<String. la traducción interna que hace Java de las clases genéricas obliga a tener en cuenta estas restricciones.Integer> mp=new Mapa<String. o una variable. Integer inx) 6.println( "Fin de aplicación. por ejemplo: la clase Mapa puede disponer del método: .1 Restricciones con tipos genéricos En general.

Esto no impide definir un contenedor de. int elementos.4 Clase genérica Pila Se trata de diseñar una clase Pila que permita manipular pilas de diferentes tipos de información.1 Operaciones básicas de una pila. T datos[]. No se permite declarar arreglos de una clase genérica. De acuerdo con la especificación de la estructura de la pila se escribe a continuación la declaración de la clase genérica Pila: public class Pila<T> { final int TAM=100. sus operaciones usuales son insertar y quitar. mientras que la segunda (pop) elimina o saca un elemento de ella. por ejemplo: objetos de tipo Terna<String>. } //añadir un elemento a la pila . como sería Pila<Terna<String>>. la primera (push) añade un elemento en su cima. una pila es una estructura que permite almacenar datos de modo que el último en entrar en la pila es el primero en salir.1 muestra una pila con las operaciones típicas. si se considera la clase: class Terna<T> {…}. no es posible el siguiente código: Terna <String> [ ] lista=new Terna<String> [20]. public Pila() { elementos=0. datos=(T[]) new Object[TAM].public T[] copiarDatos(T[] v) 4. Figura 6. 6. la Figura 6.

no hay elementos. . tales como: Pila<Integer> pilaEnt=new Pila<Integer>(). por consiguiente. Pila<String> pilaCad=new Pila<String>(). int p=elementos. } //¿Está la pila vacía? boolean vacia() { return elementos==0. } //número de elementos reales en la pila int numero() { return elementos. } } El sufijo <T> en la declaración de clases indica que se declara una plantilla de clase y que se utilizará T como el tipo de dato genérico. } //obtener un elemento de la pila T quitar() throws Exception { if (!vacia()) return datos[--elementos]."). Pila es una clase parametrizada con el tipo T como parámetro. } //leer el elemento cima de la pila T cima() throws Exception { if (vacia()) throw new Exception ("Pila vacía. Con esta definición de la plantilla de clases Pila se pueden crear pilas de diferentes tipos de datos. throw new Exception("Pila vacía"). return datos[--p].void insertar(T elem) throws Exception { if (elementos<TAM) datos[elementos++]=elem.

La primera pila permite guardar elementos de tipo Integer. se realizó una única declaración de clase en lugar de declarar una clase específica para enteros y otra para cadenas. la segunda guarda elementos de tipo cadena (String). Crear una instancia específica de pila (por ejemplo: una pila de datos de tipo Double o de tipo Empleado). .insertar("Jueves").println(pilaEnt.4.insertar(2). … 6.insertar(4). una de elementos tipo Double y otra de elementos tipo Racional.quitar()). con estas pilas se realizan las operaciones típicas: pilaEnt. pilaCad. pilaEnt.out. la clase Racional representa números racionales.insertar("Viernes"). pilaCad. el programa crea dos pilas. System. El uso de la clase genérica Pila con diversos tipos de datos se puede comprobar con el programa PilaGenerica.1 Utilización de la plantilla de una clase genérica La manipulación de una plantilla de clase requiere dos etapas: Declarar el tipo parametrizado (por ejemplo: Pila). fracciones compuestas de numerador y denominador. es decir.

Sign up to vote on this title
UsefulNot useful