sábado, 1 de diciembre de 2012

5.1 - 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 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"):

<HTML>
<HEAD>
<TITLE>Ejemplo 2 - Applet Contador</TITLE>
</HEAD>
<BODY>
<applet code="Ejemplo2.class" width=170 height=150>
</applet>
</BODY>
</HTML>

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:

<applet code="Ejemplo3.class" width=170 height=150>
</applet>

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! Aquí un ejemplo en video para que nos quede un poco mas claro la esctructura de una clase Estructura de una Clase

No hay comentarios:

Publicar un comentario