jueves, 29 de mayo de 2008

2. Las clases en Java

Las clases en Java

Bueno, antes que nada conviene saber que en Java hay un montón de clases ya definidas y utilizables.

Éstas vienen en las bibliotecas estándar:

java.lang - clases esenciales, números, strings, objetos, compilador, runtime, seguridad y threads (es el único paquete que se incluye automáticamente en todo programa Java)

java.io - clases que manejan entradas y salidas

java.util - clases útiles, como estructuras genéricas, manejo de fecha, hora y strings, número aleatorios, etc.

java.net - clases para soportar redes: URL, TCP, UDP, IP, etc.

java.awt - clases para manejo de interface gráfica, ventanas, etc.

java.awt.image - clases para manejo de imágenes

java.awt.peer - clases que conectan la interface gráfica a implementaciones dependientes de la plataforma (motif, windows)

java.applet - clases para la creación de applets y recursos para reproducción de audio.

Para que se den una idea, los números enteros, por ejemplo, son "instancias" de una clase no redefinible, Integer, que desciende de la clase Number e implementa los siguientes atributos y métodos:

public final class java.lang.Integer extends java.lang.Number {

// Atributos
public final static int MAX_VALUE;
public final static int MIN_VALUE;

// Métodos Constructores public Integer(int value); public Integer(String s);

// Más Métodos public double doubleValue(); public boolean equals(Object obj); public float floatValue(); public static Integer getInteger(String nm); public static Integer getInteger(String nm, int val); public static Integer getInteger(String nm, Integer val); public int hashCode(); public int intValue(); public long longValue(); public static int parseInt(String s); public static int parseInt(String s, int radix); public static String toBinaryString(int i); public static String toHexString(int i);

public static String toOctalString(int i);

public String toString();

public static String toString(int i);

public static String toString(int i, int radix);

public static Integer valueOf(String s);

public static Integer valueOf(String s, int radix);
}

Mucho, no?

Esto también nos da algunas ideas:

la estructura de una clase

caramba, hay métodos repetidos!

De la estructura enseguida hablaremos; en cuanto a los métodos repetidos (como parseInt por ejemplo), al llamarse al método el compilador decide cuál de las implementaciones del mismo usar basándose en la cantidad y tipo de parámetros que le pasamos. Por ejemplo, parseInt("134") y parseInt("134",16), al compilarse, generarán llamados a dos métodos distintos.

Estructura de una clase

Una clase consiste en:

algunas_palabras class nombre_de_la_clase [algo_más] {

[lista_de_atributos]

[lista_de_métodos]
}

Lo que está entre [ y ] es opcional…

Ya veremos qué poner en "algunas_palabras" y "algo_más", por ahora sigamos un poco más.

La lista de atributos (nuestras viejas variables locales) sigue el mismo formato de C: se define primero el tipo y luego el nombre del atributo, y finalmente el ";".

public final static int MAX_VALUE

;

También tenemos "algunas_palabras" adelante, pero en seguida las analizaremos.

En cuanto a los métodos, también siguen la sintaxis del C; un ejemplo:

public int incContador() {

// declaración y apertura de {

cnt++;

// instrucciones, separadas por ";"

return(cnt);

}

// cierre de }





Finalmente, se aceptan comentarios entre /* y */, como en C, o bien usando // al principio del comentario (el comentario termina al final de la línea).

Veamos un ejemplo:

// Implementación de un contador sencillo// GRABAR EN UN ARCHIVO "Contador.java" (OJO CON LAS MAYUSCULAS!)// COMPILAR CON: "javac Contador.java" (NO OLVIDAR EL .java!)// ESTA CLASE NO ES UNA APLICACION, pero nos va a servir enseguida

public class Contador { // Se define la clase Contador

// Atributos
int cnt; // Un entero para guardar
el valor actual

// Constructor // Un método constructor… public Contador() { // …lleva el mismo nombre que la clase cnt = 0; // Simplemente, inicializa (1) }

// Métodos
public int incCuenta() { // Un método para

incrementar el contador cnt++; // incrementa cnt return cnt; // y de paso devuelve el nuevo valor

} public int getCuenta() { // Este sólo devuelve el valor actual return cnt; // del contador } }

Cuando, desde una aplicación u otro objeto, se crea una instancia de la clase Contador, mediante la instrucción:

new Contador()

el compilador busca un método con el mismo nombre de la clase y que se corresponda con la llamada en cuanto al tipo y número de parámetros. Dicho método se llama Constructor, y una clase puede tener más de un constructor (no así un objeto o instancia, ya que una vez que fue creado no puede recrearse sobre sí mismo).

En tiempo de ejecución, al encontrar dicha instrucción, el intérprete reserva espacio para el objeto/ instancia, crea su estructura y llama al constructor.

O sea que el efecto de new Contador() es, precisamente, reservar espacio para el contador e inicializarlo en cero.

En cuanto a los otros métodos, se pueden llamar desde otros objetos (lo que incluye a las aplicaciones) del mismo modo que se llama una función desde C.

Por ejemplo, usemos nuestro contador en un programa bien sencillo que nos muestre cómo evoluciona:

// Usemos nuestro contador en una mini-aplicación
// GRABAR EN UN ARCHIVO "Ejemplo1.java" (OJO CON LAS MAYUSCULAS!)

// COMPILAR CON:

"javac Ejemplo.java"

(NO OLVIDAR EL .

java!)

// EJECUTAR CON:

"java Ejemplo1"

(SIN el .java)

import java.io.*; // Uso la biblioteca de
entradas/salidas

public class Ejemplo1 { // IMPORTANTE: Nombre de la clase

// igual al nombre del archivo!
// entero para asignarle el valor del contador e imprimirlo
// aunque en realidad no me hace falta.
static int n;
// y una variable tipo Contador para instanciar el objeto…
static Contador laCuenta;

// ESTE METODO, MAIN, ES EL QUE HACE QUE ESTO SE COMPORTE
// COMO APLICACION. Es donde arranca el programa cuando ejecuto "java

Ejemplo1"
// NOTA: main debe ser public & static.
public static void main ( String args[] ) {

System.out.println ("Cuenta… "); // Imprimo el título laCuenta = new Contador(); // Creo una instancia del Contador System.out.println (laCuenta.getCuenta()); // 0 - Imprimo el valor

Java desde Cero

actual (cero!)

n = laCuenta.incCuenta();

// 1 - Asignación e

incremento

System.out.println (n);

// Ahora imprimo n

laCuenta.incCuenta();

// 2 - Lo incremento (no

uso el valor…

System.out.println (laCuenta.getCuenta());

// …de retorno) y lo imprimo

System.out.println (laCuenta.incCuenta());

// 3 - Ahora todo en un

paso!

}

}




En el capítulo III vamos a analizar este programa en detalle. Por ahora veamos la diferencia con un applet que haga lo mismo:

// Applet de acción similar a la aplicación Ejemplo1 // GRABAR EN ARCHIVO: "Ejemplo2.java" // COMPILAR CON: "javac Ejemplo2.java" // PARA EJECUTAR: Crear una página HTML como se indica luego

import java.applet.*;
import java.awt.*;

public class Ejemplo2 extends Applet {
static int n;
static Contador laCuenta;

// Constructor…
public Ejemplo2 () {
laCuenta = new Contador();
}

// El método paint se ejecuta cada vez que hay que redibujar
// NOTAR EL EFECTO DE ESTO CUANDO SE CAMBIA DE TAMAÑO LA
// VENTANA DEL NAVEGADOR!
public void paint (Graphics g) {

g.drawString ("Cuenta...", 20, 20);
g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 35 );
n = laCuenta.incCuenta();
g.drawString (String.valueOf(n), 20, 50 );
laCuenta.incCuenta();
g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 65 );
g.drawString (String.valueOf(laCuenta.incCuenta()), 20, 80 );

}
}

Ahora es necesario crear una página HTML para poder visualizarlo. Para esto, crear y luego cargar el archivo ejemplo2.htm con un browser que soporte Java (o bien ejecutar en la ventana DOS: "appletviewer ejemplo2.htm"):



Ejemplo 2 - Applet Contador







Para terminar este capítulo, observemos las diferencias entre la aplicación standalone y el applet:

La aplicación usa un método main, desde donde arranca

El applet, en cambio, se arranca desde un constructor (método con el mismo nombre que la clase)

Además:

En la aplicación utilizamos System.out.println para imprimir en la salida estándar

En el applet necesitamos "dibujar" el texto sobre un fondo gráfico, por lo que usamos el método g. drawString dentro del método paint (que es llamado cada vez que es necesario redibujar el applet)

Con poco trabajo se pueden combinar ambos casos en un solo objeto, de modo que la misma clase sirva para utilizarla de las dos maneras:

// Archivo: Ejemplo3.java
// Compilar con: javac Ejemplo3.java
import java.applet.*;
import java.awt.*;
import java.io.*;

public class Ejemplo3 extends Applet {
static int n;
static Contador laCuenta;

public Ejemplo3 () {
laCuenta = new Contador();

}

public static void main(String args[]) {
laCuenta = new Contador();
paint();

}

public static void paint () {
System.out.println ("Cuenta...");
System.out.println (laCuenta.getCuenta());
n = laCuenta.incCuenta();
System.out.println (n);
laCuenta.incCuenta();
System.out.println (laCuenta.getCuenta());
System.out.println (laCuenta.incCuenta());

}

public void paint (Graphics g) {
g.drawString ("Cuenta...", 20, 20);
g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 35 );
n = laCuenta.incCuenta();
g.drawString (String.valueOf(n), 20, 50 );
laCuenta.incCuenta();
g.drawString (String.valueOf(laCuenta.getCuenta()), 20, 65 );
g.drawString (String.valueOf(laCuenta.incCuenta()), 20, 80 );

}
}

Esta clase puede ejecutarse tanto con "java Ejemplo3" en una ventana DOS, como cargarse desde una página HTML con:




Notar que conviene probar el applet con el appletviewer ("appletviewer ejemplo3.htm"), ya que éste indica en la ventana DOS si hay algún error durante la ejecución. Los browsers dejan pasar muchos errores, simplemente suprimiendo la salida a pantalla del código erróneo.

Notar que en todo este desarrollo de las clases Ejemplo1, Ejemplo2 y Ejemplo3, en ningún momento volvimos a tocar la clase Contador!

En el próximo capítulo analizaremos el código línea por línea para ir comprendiendo los distintos elementos que allí aparecen.

No hay comentarios: