La plataforma Java nos proporciona un amplio conjunto de clases dentro del que podemos encontrar tipos de datos que nos resultarán muy útiles para realizar la programación de aplicaciones en Java. Estos tipos de datos nos ayudarán a generar código más limpio de una forma sencilla.
Un wrapper es un objeto que se utiliza para envolver a otro. De esta forma, podemos "encapsular" un objeto dentro de otro, y acceder al objeto encapsulado a través del objeto que lo encapsula. Veremos durante el curso que en Java se utilizan Wrappers en diferentes ámbitos.
Hemos visto que en Java cualquier tipo de datos es un objeto, excepto los tipos de datos básicos: boolean, int, long, float, double, byte, short, char.
Si queremos agrupar diferentes elementos de estos tipos en un solo objeto, la única forma aparente de hacerlo es crear un array de ese tipo (por ejemplo, un array de int[ ]). Pero tenemos el inconveniente de que los arrays deben tener un tamaño estático. ¿Qué pasa si queremos tener una lista o colección de estos elementos, que vaya variando su tamaño? Cuando trabajamos con colecciones o listas de datos los elementos que contienen éstas son siempre objetos, por lo que en un principio no podríamos insertar elementos de estos tipos básicos. Para hacer esto posible tenemos una serie de objetos que se encargarán de envolver a estos tipos básicos, permitiéndonos tratarlos como objetos y por lo tanto insertarlos como elementos de listas. Estos objetos son los llamados wrappers, y las clases en las que se definen tienen nombre similares al del tipo básico que encapsulan, con la diferencia de que comienzan con mayúscula: Boolean, Integer, Long, Float, Double, Byte, Short, Character.
Estas clases, además de servirnos para encapsular estos datos básicos en forma de objetos, nos proporcionan una serie de métodos e información útiles para trabajar con estos datos. Nos proporcionarán métodos por ejemplo para convertir cadenas a datos numéricos de distintos tipos y viceversa, así como información acerca del valor mínimo y máximo que se puede representar con cada tipo numérico.
Ejemplos:
String unNumero = "123";
String otroNumero = "145.5";
int elNumero = Integer.parseInt(unNumero);
double elOtroNumero = Double.parseDouble(otroNumero);
esto sería útil por ejemplo para tomar valores numéricos de parámetros del programa, y pasarlos a un valor numérico verdadero para poder operar con él.
También podemos encapsular un valor simple dentro de su wrapper, y luego añadirlo a una lista (veremos las listas y colecciones más adelante):
int miNumero = 20;
Vector v = new Vector();
v.add(miNumero); // No está permitido!! No podemos poner tipos simples en Vectores
Integer intobj = new Integer(miNumero); v.add(intobj); // Esto sí está permitido // ¿Cómo recuperamos luego el entero? Integer elemento = (Integer)(v.elementAt(0)); // Sacamos el wrapper del vector int miValor = elemento.intValue(); // Y luego sacamos el valor del wrapper
esto lo utilizaremos cuando veamos las colecciones, para añadir a ellas tipos simples y luego recuperarlos.
Utiliza la clase sesion06.Ej4 que se proporciona en la plantilla para construir un programa que tome como parámetro (en el main) dos valores reales (doubles), y Muestre por pantalla el producto del primero y el segundo.
Captura la(s) excepcion(es) que consideres adecuadas para asegurarte de que el dato que se pasa como parámetro es numérico.
AYUDAS: utiliza la clase Double, y mira entre sus métodos cuáles pueden servirte para convertir los parámetros a números reales. Echa un vistazo a la clase Ej1 que hiciste en la sesión de excepciones. Puede que te dé alguna pista de cómo hacer este otro ejercicio.
Esta es la clase base de todas las clases en Java, toda clase hereda en última instancia de la clase Object, por lo que los métodos que ofrece estarán disponibles en cualquier objeto Java, sea de la clase que sea.
En Java es importante distinguir claramente entre lo que es una variable, y lo que es un objeto. Las variables simplemente son referencias a objetos, mientras que los objetos son las entidades instanciadas en memoria que podrán ser manipulados mediante las referencias que tenemos a ellos (mediante variable que apunten a ellos) dentro de nuestro programa. Cuando hacemos lo siguiente:
new MiClase()
Se está instanciando en memoria un nuevo objeto de clase MiClase y nos devuelve una referencia a dicho objeto. Nosotros deberemos guardarnos dicha referencia en alguna variable con el fin de poder acceder al objeto creado desde nuestro programa:
MiClase mc = new MiClase();
Es importante declarar la referencia del tipo adecuado (en este caso tipo MiClase) para manipular el objeto, ya que el tipo de la referencia será el que indicará al compilador las operaciones que podremos realizar con dicho objeto. El tipo de esta referencia podrá ser tanto el mismo tipo del objeto al que vayamos a apuntar, o bien el de cualquier clase de la que herede o interfaz que implemente nuestro objeto. Por ejemplo, si MiClase se define de la siguiente forma:
public class MiClase extends Thread implements List { ... }
Podremos hacer referencia a ella de diferentes formas:
MiClase mc = new MiClase(); Thread t = new MiClase(); List l = new MiClase(); Object o = new MiClase();
Esto es así ya que al heredar tanto de Thread como de Object, sabemos que el objeto tendrá todo lo que tienen estas clases más lo que añada MiClase, por lo que podrá comportarse como cualquiera de las clases anteriores. Lo mismo ocurre al implementar una interfaz, al forzar a que se implementen sus métodos podremos hacer referencia al objeto mediante la interfaz ya que sabemos que va a contener todos esos métodos. Siempre vamos a poder hacer esta asignación 'ascendente' a clases o interfaces de las que deriva nuestro objeto.
Si hacemos referencia a un objeto MiClase mediante una referencia Object por ejemplo, sólo podremos acceder a los métodos de Object, aunque el objeto contenga métodos adicionales definidos en MiClase. Si conocemos que nuestro objeto es de tipo MiClase, y queremos poder utilizarlo como tal, podremos hacer una asignación 'descendente' aplicando una conversión cast al tipo concreto de objeto:
Object o = new MiClase(); ... MiClase mc = (MiClase) o;
Si resultase que nuestro objeto no es de la clase a la que hacemos cast, ni hereda de ella ni la implementa, esta llamada resultará en un ClassCastException indicando que no se puede hacer la conversión del tipo: no podemos hacer referencia a dicho objeto mediante esa interfaz debido a que el objeto no la cumple, y por lo tanto podrán no estar disponibles los métodos que se definen en ella.
Una vez hemos visto la diferencia entre las variables (referencias) y objetos (entidades) vamos a ver como se hará la asignación y comparación de objetos. Si hiciesemos lo siguiente:
MiClase mc1 = new MiClase(); MiClase mc2 = mc1;
Puesto que hemos dicho que las variables simplemente son referencias a objetos, la asignación estará copiando una referencia, no el objeto. Es decir, tanto la variable mc1 como mc2 apuntarán a un mismo objeto.
Si lo que queremos es copiar un objeto, teniendo dos entidades independientes, deberemos invocar el método clone del objeto a copiar:
MiClase mc2 = (MiClase)mc1.clone();
El método clone es un método de la clase Object que estará disponible para cualquier objeto Java, y nos devuelve un Object genérico, ya que al ser un método que puede servir para cualquier objeto nos debe devolver la copia de este tipo. De él tendremos que hacer una conversión cast a la clase de la que se trate como hemos visto en el ejemplo.
Por otro lado, para la comparación, si hacemos lo siguiente:
mc1 == mc2
Estaremos comparando referencias, por lo que estaremos viendo si las dos referencias apuntan a un mismo objeto, y no si los objetos a los que apuntan son iguales. Para ver si los objetos son iguales, aunque sean entidades distintas, tenemos:
mc1.equals(mc2)
Este método también es propio de la clase Object, y será el que se utilice para comparar internamente los objetos.
Tanto clone como equals, deberán ser redefinidos en nuestras clases para adaptarse a éstas. Deberemos especificar dentro de ellos como se copia nuestro objeto y como se compara si son iguales:
public class Punto2D { public int x, y; ... public boolean equals(Object o) { Punto2D p = (Punto2D)o; // Compara objeto this con objeto p return (x == p.x && y == p.y); } public Object clone() { Punto2D p = new Punto2D(); // Construye nuevo objeto p // copiando los atributos de this p.x = x; p.y = y; return p; }
Un último método interesante de la clase Object es toString. Este método nos devuelve una cadena (String) que representa dicho objeto. Por defecto nos dará un identificador del objeto, pero nosotros podemos sobrescribirla en nuestras propias clases para que genere la cadena que queramos. De esta manera podremos imprimir el objeto en forma de cadena de texto, mostrandose los datos con el formato que nosotros les hayamos dado en toString. Por ejemplo, si tenemos una clase Punto2D, sería buena idea hacer que su conversión a cadena muestre las coordenadas (x,y) del punto:
public class Punto2D { public int x,y; ... public String toString() { String s = "(" + x + "," + y + ")"; return s; } }
La cadena que devuelve este método puede utilizarse después en la salida que queramos: sacarla por pantalla (con System.out.println), volcarla a un cuadro de texto... etc.
Echa un vistazo a la clase sesion06.Ej5 de la plantilla. Verás que hay una clase interna llamada MiObject que contiene un valor entero y una cadena. Tiene un constructor para poder asignar valor a cada campo. Después, desde la clase principal Ej5 se crean varios objetos de este tipo, cada uno con un valor entero y una cadena. Después se utiliza el método equals para compararlos entre sí, e indicar si son iguales o no. Finalmente, se imprime por pantalla cada uno de los objetos creados.
Asumismos que dos objetos de tipo MiObject son iguales si sus campos enteros son iguales, y si sus cadenas también son iguales. Teniendo en cuenta todo esto:
Probablemente habrás descubierto que las comparaciones no funcionan del todo bien: m1 y m2 son aparentemente iguales, y sin embargo dice que son diferentes. También habrás visto que a la hora de imprimir el objeto saca una ristra de caracteres que no se entienden. Vamos a corregir todo esto por separado.
public boolean equals(Object o)
{
...
}y rellénalo de forma adecuada para que devuelva true si el objeto o es igual al actual (this), es decir, si tiene su campo entero y su campo cadena igual al actual.
AYUDA: observa que tendrás que convertir el objeto o a tipo MiObject para poder comparar. El método equals exige que el objeto que se le pasa como parámetro sea SIEMPRE de tipo Object, para poder hacer bien la herencia y sobreescritura del método equals original. Después, en el código, deberemos convertir este objeto al tipo concreto con que trabajemos:
MiObject mo = (MiObject) o;
public String toString()
{
...
}y haz que devuelva una cadena conteniendo el número entero, una coma, y la cadena del objeto MiObject.
Esta clase nos ofrece una serie de métodos y campos útiles del sistema. Esta clase no se debe instanciar, todos estos métodos y campos son estáticos.
Podemos encontrar los objetos que encapsulan la entrada, salida y salida de error estándar, así como métodos para redireccionarlas, que veremos con más detalle en el tema de entrada/salida.
Otros métodos útiles que encontramos son:
void exit(int estado)
Finaliza la ejecución de la aplicación, devolviendo un código de estado. Normalmente el código 0 significa que ha salido de forma normal, mientras que con otros códigos indicaremos que se ha producido algún error.
void gc()
Fuerza una llamada al colector de basura para limpiar la memoria. Esta es una operación costosa. Normalmente no lo llamaremos explicitamente, sino que dejaremos que Java lo invoque cuando sea necesario.
long currentTimeMillis()
Nos devuelve el tiempo medido en el número de milisegundos transcurridos desde el 1 de Enero de 1970 a las 0:00.
void arraycopy(Object fuente, int pos_fuente, Object destino, int pos_dest, int n)
Copia n elementos del array fuente, desde la posición pos_fuente, al array destino a partir de la posición pos_dest.
String getProperty(String propiedad)
El sistema tiene una serie de propiedades, identificadas por un nombre. A continuación mostramos una lista con diferentes nombres de propiedades del sistema, y qué significan:
Clave | Contenido |
file.separator |
Separador entre directorios en la ruta de los ficheros. Por ejemplo "/" en UNIX. |
java.class.path |
Classpath de Java |
java.class.version |
Versión de las clases de Java |
java.home |
Directorio donde está instalado Java |
java.vendor |
Empresa desarrolladora de la implementación de la plataforma Java instalada |
java.vendor.url |
URL de la empresa |
java.version |
Versión de Java |
line.separator |
Separador de fin de líneas utilizado |
os.arch |
Arquitectura del sistema operativo |
os.name |
Nombre del sistema operativo |
os.version |
Versión del sistema operativo |
path.separator |
Separador entre los distintos elementos de una variable de entorno tipo PATH. Por ejemplo ":" |
user.dir |
Directorio actual |
user.home |
Directorio de inicio del usuario actual |
user.name |
Nombre de la cuenta del usuario actual |
Por ejemplo, si hacemos:
String barra = System.getProperty("file.separator");
estaremos obteniendo el símbolo con el que el sistema operativo separa los nombres de carpetas, subcarpetas y ficheros (será "/" en Linux y "\" en Windows).
Otro ejemplo:
System.out.println(System.getProperty("line.separator"));
en este caso, estamos sacando por pantalla el salto de línea propio del sistema operativo. Esto puede sernos útil si, como veremos más adelante, imprimimos este símbolo en un fichero, para así hacer los saltos de línea de acuerdo con el sistema operativo en el que estemos. Si abrís un fichero de texto Windows en Linux, veréis que los finales de línea contienen caracteres extraños (una M mayúscula con con otro color). Esto es porque la secuencia de caracteres que emplea Windows para indicar fin de línea es diferente a la empleada en Linux, y los caracteres que no reconoce los muestra.
Podemos obtener todas las propiedades del sistema en un objeto Properties:
Properties getProperties()
Este objeto, que veremos al hablar de entrada/salida, contiene una lista de elementos, en este caso las propiedades del sistema, que podemos fácilmente guardar y leer. En el tema de entrada/salida se explicará cómo trabajar con este tipo de datos.
Toda aplicación Java tiene una instancia de la clase Runtime que se encargará de hacer de interfaz con el entorno en el que se está ejecutando. Para obtener este objeto debemos utilizar el siguiente método estático:
Runtime rt = Runtime.getRuntime();
Una de las operaciones que podremos realizar con este objeto, será ejecutar comandos como si nos encontrásemos en la línea de comandos del sistema operativo. Para ello utilizaremos el siguiente método:
rt.exec(comando);
donde comando puede ser una cadena con el comando entero (incluyendo parámetros) que queremos ejecutar, o un array donde se separen el comando y cada parámetro, u otras posibilidades (consultad el API para ver todas las variantes). De esta forma podremos invocar programas externos desde nuestra aplicación Java.
En la clase sesion06.Ej6 vamos a ejecutar una aplicación externa a Java. Por ejemplo, vamos a abrir el navegador Internet Explorer, y el bloc de notas.
C:\Archivos de programa\Internet Explorer\iexplore.exe
C:\Windows\notepad.exe(la carpeta C:/Windows puede ser C:/Winnt si estás trabajando con Windows 2000 o NT). Guadaremos cada ruta en una cadena:
String ruta = "C:\\Archivos de programa\\Internet Explorer\\iexplore.exe";
String ruta2 = "C:\\Windows\\notepad.exe";Observa que las barras invertidas \ se deben poner dobles en las variables String (es una secuencia de escape para guardar la barra, igual que \n guarda un salto de línea). También funcionará si en lugar de barras invertidas ponemos barras simples "/", y en este caso no hace falta duplicar:
String ruta = "C:/Archivos de programa/Internet Explorer/iexplore.exe";
String ruta2 = "C:/Windows/notepad.exe";
Supongamos que tenemos un objeto Runtime creado, y listo para ejecutar dos comandos guardados en las cadenas com1 y com2:
Runtime rt = Runtime.getRuntime();
String com1 = "C:/comando1.exe";
String com2 = "C:/comando2.exe";Si hacemos un exec con el primero y luego un exec con el segundo, se ejecutarán los dos a la vez, como habrás podido comprobar:
rt.exec(com1);
rt.exec(com2);Observa que la llamada a exec realmente devuelve un objeto de tipo Process (consulta el API). Podemos quedarnos con este objeto, y hacer que el programa actual (el hilo principal de Java) espere a que termine ese proceso Process antes de pasar a la siguiente línea de código:
Process p = rt.exec(com1);
p.waitFor();
rt.exec(com2);Aplica este esquema sobre el ejercicio, para que primero se abra el navegador, y cuando lo cierres, se abra el bloc de notas. Captura, como antes, las excepciones que se te pidan al compilar.
La clase Math nos será de gran utilidad cuando necesitemos realizar operaciones matemáticas. Esta clase no necesita ser instanciada, ya que todos sus métodos son estáticos. Entre estos métodos podremos encontrar todas las operaciones matemáticas básicas que podamos necesitar, como logaritmos, exponenciales, funciones trigonométricas, generación de números aleatorios, conversión entre grados y radianes, etc. Además nos ofrece las constantes de los números PI y E.
La clase java.util.Date nos servirá para almacenar una determinada fecha y hora, que podrán ser las actuales, o las de un momento determinado (por ejemplo, el 3 de junio de 2002, a las 13:32 horas).
Si queremos obtener la fecha actual, construimos un objeto Date sin parámetros y ya está:
Date d = new Date();
Si queremos construir una fecha y hora concretas, indicando día, mes, año, hora, minuto o segundo, veréis en la API que la clase Date tiene constructores y métodos para establecer todos estos valores por separado:
public Date(int año, int mes, int dia);
public Date(int año, int mes, int dia, int hora, int minuto, int segundo);
public void setYear(int año);
public void setHours(int hora);
...
y construir así una fecha diferente. Sin embargo, consultando la API, veréis que todos estos métodos están deprecated (desaconsejados), y la documentación indica que Date sólo debe utilizarse para obtener la fecha actual (de la forma que hemos visto antes), y se debe utilizar la clase java.util.Calendar para especificar otras fechas concretas. Además, la clase Calendar nos servirá para realizar operaciones con fechas, comparar fechas, u obtener distintas representaciones para mostrar la fecha en nuestra aplicación.
Para ello, primero deberemos obtener una instancia de un objeto de tipo Calendar, con:
Calendar c = Calendar.getInstance();
Una vez obtenido, el objeto Calendar almacenará la fecha y hora actuales, pero luego podremos construir una fecha propia utilizando métodos como:
void set(int anyo, int mes, int dia, int hora, int minuto, int segundo)
y otros similares. Veréis que hay varias modalidades del método set, y otros alternativos, como setTime, setTimeInMillis, etc.
También podremos obtener por partes los elementos de la fecha, llamando al método get, e indicándole como parámetro qué parte queremos obtener. Para ello, la clase Calendar dispone de varias constantes para indicar cada una de las partes por separado.
int anyo = c.get(Calendar.YEAR);
int mes = c.get(Calendar.MONTH) + 1;
int dia = c.get(Calendar.DAY_OF_MONTH);
int hora = c.get(Calendar.HOUR_OF_DAY);
int minuto = c.get(Calendar.MINUTE);
int segundo = c.set(Calendar.SECOND);
System.out.println ("La fecha es " + dia + "/" + mes + "/" + anyo + ", " + hora + ":" + minuto + ":" + segundo);
Observa que luego podemos tomar las partes que necesitemos y representarlas como queramos. Observa también que cuando obtenemos el mes a través de la constante Calendar.MONTH, el mes se nos devuelve con valores entre 0 y 11, por lo que le deberemos sumar 1 para poner el número de mes correcto.
Muchas veces queremos sacar por pantalla o en un cuadro de texto un valor numérico, o una fecha, y no tenemos forma cómoda de específicar con qué formato queremos mostrarlos: si con 2 decimales, o si poniendo el año con 4 dígitos... etc.
Para esto Java pone a nuestra disposición clases como java.text.NumberFormat (para formatear números) o java.text.DateFormat (para formatear fechas).
Para poder formatear números, primero debemos obtener una instancia del objeto NumberFormat . Normalmente suele hacerse con:
NumberFormat nf = NumberFormat.getInstance();
Una vez obtenido, la clase NumberFormat tiene diversos métodos para indicar cómo queremos que salga el número. Por ejemplo:
setMinimumIntegerDigits(int n);
Establece que el mínimo número de cifras enteras que hay que mostrar sea de n cifras. Si por ejemplo n fuese 4, y queremos sacar un número como 23, lo que se mostraría finalmente sería "0023".
setMaximumIntegerDigits(int n);
Parecido al anterior, pero a la inversa: establece que el máximo número de cifras enteras que hay que mostrar sea de n cifras. Si queremos mostrar 4567 y n es 3, en este caso mostraría "567".
setMinimumFractionDigits(int n);
setMaximumFractionDigits(int n);
Similares a los dos métodos anteriores, pero para establecer cuántas cifras decimales queremos que tenga el número como mínimo y como máximo.
setGroupingUsed(boolean grouping);
El grouping used indica si queremos que se agrupen los dígitos para indicar los miles, millones, etc, o si queremos simplemente mostrar la secuencia de dígitos que componen el número. Si le pasamos true a este método, un número como 4567 se representará como "4.567", y si le pasamos false lo representará tal cual está, como "4567". Podemos ver si está activado o no este flag booleano en cada momento, con:
boolean isGroupingUsed(boolean grouping);
La idea es llamar a estos métodos después de haber instanciado nuestro objeto NumberFormat, y una vez lo tengamos todo configurado, formatear el número o números que queramos llamando al método format de NumberFormat (veréis que hay varias formas de utilizarlo en el API). Por ejemplo:
double num1 = 1623.5;
NumberFormat nf = NumberFormat.getInstance();
nf.setMinimumFractionDigits(3);
nf.setMinimumIntegerDigits(5);
nf.setGroupingUsed(true);
String valorFormateado vf = nf.format(num1);
System.out.println(vf);
mostraría por pantalla el número "01.623,500".
Al igual que con NumberFormat, para poder formatear fechas también deberemos obtener previamente una instancia de objeto DateFormat. Podríamos utilizar el método getInstance() de DateFormat, al igual que hacemos con NumberFormat. Sin embargo, nos vamos a valer de la subclase java.text.SimpleDateFormat, que nos permitirá dar un formato más cómodo a las fechas:
DateFormat df = new SimpleDateFormat(String patron);
El patron es una cadena de texto que indicará cómo se debe presentar la fecha. Algunos ejemplos:
"dd / MM / yyyy"
muestra el día con dos dígitos, una barra, el mes con dos dígitos, una barra y el año con 4 dígitos.
"dd - MMMMM - yyyy, hh:mm:ss"
muestra el día con dos dígitos, un guión, el mes con letras, un guión, el año con 4 dígitos, coma, y luego la hora actual, dos puntos, minutos actuales, dos puntos y segundos actuales.
A la luz de los anteriores ejemplos, podemos extraer que, dentro de la cadena del patrón:
Podéis consultar la API de SimpleDateFormat para más información sobre otros posibles caracteres. Aquí ponemos un ejemplo de uso, combinando lo anterior:
DateFormat df = new SimpleDateFormat("dd - MMMMM - yyyy, hh:mm:ss");
// Fecha actual
Date d = new Date();
// Sacará la fecha actual con el formato indicado, por ejemplo: "05 - julio - 2005, 12:54:23"
System.out.println (df.format(d));
Utiliza el método main de la clase sesion06.Ej7 de la plantilla para calcular el logaritmo neperiano del número real (double) que se le pase como parámetro. Guarda ese número en una variable de tipo double y utiliza después un NumberFormat para mostrarla por pantalla, con un mínimo de 3 cifras decimales y un máximo de 5, y sin punto para separar los miles (es decir, sin grouping used).
AYUDA: para calcular el logaritmo deberás utilizar el método log de la clase Math.
Haz que la clase sesion06.Ej8 lance un hilo que cada 200 ms esté calculando la fecha actual, y guardándola en la variable global Calendar que tiene Ej8. El hilo principal (Ej8) estará en un bucle infinito donde dormirá 1 segundo, y luego mostrará por pantalla la fecha que tenga su campo Calendar, con el siguiente formato:
<día> del <mes_en_cifra> de <año>, a las <hora>:<minuto>:<segundo>
por ejemplo:
23 del 03 de 2005, a las 21:15:23
AYUDA: para colocar texto dentro del patrón de la fecha (por ejemplo, 'del', o 'a las'), colócalo con comillas simples, insertándolo dentro del patrón con comillas dobles. Por ejemplo:
"dd 'del' MM 'de' yyyy"
El funcionamiento del hilo principal, una vez lanzado el segundo hilo, deberá ser el siguiente:
while (true)
{
dormir 1000 milisegundos
imprimir por pantalla la fecha del campo c (el otro hilo se encargará de actualizarla), formateada como se indica en el ejercicio
}
Este código deberá estar en el constructor de Ej8, justo después de crear y lanzar un hilo (Thread), que en su método run hará lo siguiente:
while (true)
{
dormir 200 milisegundos
actualizar el valor del campo c
}
recuerda que para poder trabajar con el hilo, deberás hacer que la clase principal implemente Runnable, y luego definir un método run con el código del segundo hilo, tal y como se ha indicado antes.
NOTAS:
c = Calendar.getInstance();
DateFormat df = ... // configurar el formato del DateFormat
...
System.out.print(df.format(c.getTime()) + "\r");El colocar el "\r" al final hará que al volver a imprimir machaque la misma línea una y otra vez, con lo que quedará más elegante que ver cada vez una línea más abajo en la pantalla. Esta característica no funcionará bien si la salida la veis en la consola de Eclipse, donde probablemente sacará una línea para cada nueva fecha. No os preocupéis por eso, simplemente probad que el programa funciona.
Si miramos dentro del paquete java.util, podremos encontrar una serie de clases que nos podrán resultar útiles para determinadas aplicaciones.
Por ejemplo, podemos encontrar la clase Currency con información monetaria. La clase Locale almacena información sobre una determinada región del mundo, por lo que podremos utilizar esta clase junto a las anteriores para obtener la moneda de una determinada zona, o las diferencias horarias y de representación de fechas.Hemos visto que Java nos permite escribir facilmente un código limpio y mantenible. Sin embargo, en muchas ocasiones además nos interesará que el código sea rápido en determinadas funciones críticas. A continuación damos una serie de consejos para optimizar el código Java:
PARA ENTREGAR
Guarda en la carpeta modulo2 de tu CVS los siguientes elementos para esta sesión: