curso java - foro lospillaos

92
FASES PARA LA ELABORACIÓN DE UN PROGRAMA INFORMÁTICO El desarrollo de un programa o de un conjunto de aplicaciones se basa en un concepto llamado ciclo de vida. Son una serie de etapas o fases que hay que seguir secuencialmente. Las fases o etapas son: • Análisis. • Diseño. • Codificación o construcción. • Implantación o explotación. • Mantenimiento. Paso a explicar las fases: ANÁLISIS En esta fase se establece el producto a desarrollar, siendo necesario especificar los procesos y estructuras de datos que se van a emplear. Debe existir una gran comunicación entre el usuario y el analista para poder conocer todas las necesidades que precisa la aplicación. En el caso de falta de información por parte del usuario se puede recurrir al desarrollo de prototipos para saber con más precisión sus requerimientos. En el análisis estructurado se pueden emplear varias técnicas como: Diagramas de flujo de datos: Sirven para conocer el comportamiento del sistema mediante representaciones gráficas. Modelos de datos: Sirven para conocer las estructuras de datos y sus características. (Entidad relación y formas normales) Diccionario de datos: Sirven para describir todos los objetos utilizados en los gráficos, así como las estructuras de datos. Definición de los interfaces de usuario: Sirven para determinar la información de entrada y salida de datos. Al final de esta fase tenemos que tener claro las especificaciones de la aplicación. DISEÑO En esta fase se alcanza con mayor precisión una solución óptima de la aplicación, teniendo en cuenta los recursos físicos del sistema (tipo de ordenador, periféricos, comunicaciones, etc…) y los recursos lógicos. (sistema operativo., programas de utilidad, bases de datos, etc…) En el diseño estructurado se pueden definir estas etapas: Diseño externo: Se especifican los formatos de información de entrada y salida. (pantalla y listados) Diseño de datos: Establece las estructuras de datos de acuerdo con su soporte físico y lógico. (estructuras en memoria, ficheros y hojas de datos)

Upload: alexander-vicente-romani

Post on 12-Jan-2016

232 views

Category:

Documents


0 download

DESCRIPTION

CURSO JAVA

TRANSCRIPT

Page 1: Curso Java - Foro Lospillaos

FASES PARA LA ELABORACIÓN DE UN PROGRAMA INFORMÁTICO El desarrollo de un programa o de un conjunto de aplicaciones se basa en un concepto llamado ciclo de vida. Son una serie de etapas o fases que hay que seguir secuencialmente.

Las fases o etapas son:

• Análisis. • Diseño. • Codificación o construcción. • Implantación o explotación. • Mantenimiento.

Paso a explicar las fases:

ANÁLISIS

En esta fase se establece el producto a desarrollar, siendo necesario especificar los procesos y estructuras de datos que se van a emplear. Debe existir una gran comunicación entre el usuario y el analista para poder conocer todas las necesidades que precisa la aplicación. En el caso de falta de información por parte del usuario se puede recurrir al desarrollo de prototipos para saber con más precisión sus requerimientos. En el análisis estructurado se pueden emplear varias técnicas como:

Diagramas de flujo de datos: Sirven para conocer el comportamiento del sistema mediante representaciones gráficas.

Modelos de datos: Sirven para conocer las estructuras de datos y sus características. (Entidad relación y formas normales)

Diccionario de datos: Sirven para describir todos los objetos utilizados en los gráficos, así como las estructuras de datos.

Definición de los interfaces de usuario: Sirven para determinar la información de entrada y salida de datos.

Al final de esta fase tenemos que tener claro las especificaciones de la aplicación.

DISEÑO En esta fase se alcanza con mayor precisión una solución óptima de la aplicación, teniendo en cuenta los recursos físicos del sistema (tipo de ordenador, periféricos, comunicaciones, etc…) y los recursos lógicos. (sistema operativo., programas de utilidad, bases de datos, etc…)

En el diseño estructurado se pueden definir estas etapas:

Diseño externo: Se especifican los formatos de información de entrada y salida. (pantalla y listados)

Diseño de datos: Establece las estructuras de datos de acuerdo con su soporte físico y lógico. (estructuras en memoria, ficheros y hojas de datos)

Diseño modular: Es una técnica de representación en la que se refleja de forma descendente la división de la aplicación en módulos. Está basado en diagramas de flujo de datos obtenidos en el análisis.

Diseño procedimental: Establece las especificaciones para cada módulo, escribiendo el algoritmo necesario que permita posteriormente una rápida codificación. Se emplean técnicas de programación estructurada, normalmente ordinogramas y pseudocódigo.

Al final de esta etapa se obtiene el denominado cuaderno de carga.

CODIFICACIÓN Consiste en traducir los resultados obtenidos a un determinado lenguaje de programación, teniendo en cuenta las especificaciones obtenidas en el cuaderno de carga. Se deben de realizar las pruebas necesarias para comprobar la calidad y estabilidad del programa.

Las pruebas se pueden clasificar en:

Pruebas unitarias: Sirven para comprobar que cada módulo realice bien su tarea.

Page 2: Curso Java - Foro Lospillaos

Pruebas de interconexión: Sirven para comprobar en el programa el buen funcionamiento en conjunto de todos sus módulos.

Pruebas de integración: Sirven para comprobar el funcionamiento correcto del conjunto de programas que forman la aplicación. (el funcionamiento de todo el sistema)

EXPLOTACIÓN En esta fase se realiza la implantación de la aplicación en el sistema o sistemas físicos donde van a funcionar habitualmente y su puesta en marcha para comprobar el buen funcionamiento.

Actividades a tener en cuenta o realizar:

• Instalación del/los programa/s. • Pruebas de aceptación al nuevo sistema. • Conversión de la información del antiguo sistema al nuevo (si hay una aplicación antigua) • Eliminación del sistema anterior.

Al final de esta fase se debe de completar la información al usuario respecto al nuevo sistema y su uso. Así como facilitarle toda la documentación necesaria para una correcta explotación del sistema (manual de ayuda, manual de uso, guía de la aplicación, etc.)

MANTENIMIENTO Esta es la fase que completa el ciclo de vida y en ella nos encargaremos de solventar los posibles errores o deficiencias de la aplicación. Existe la posibilidad de que ciertas aplicaciones necesiten reiniciar el ciclo de vida.

Tipos de mantenimiento:

Mantenimiento correctivo: Consiste en corregir errores no detectados en pruebas anteriores y que aparezcan con el uso normal de la aplicación. Este mantenimiento puede estar incluido en la garantía o mantenimiento de la aplicación.

Mantenimiento adaptativo: Consiste en modificar el programa a causa de cambio de entorno gráfico y lógico en el que estén implantados. (nuevas generaciones de ordenadores, nuevas versiones del sistema operativo, etc.)

Mantenimiento perfectivo: Consiste en una mejora sustancial de la aplicación al recibir por parte de los usuarios propuestas sobre nuevas posibilidades y modificaciones de las existentes.

Los tipos de mantenimiento adaptativo y perfectivo reinician el ciclo de vida, debiendo proceder de nuevo al desarrollo de cada una de sus fases para obtener un nuevo producto.

Page 3: Curso Java - Foro Lospillaos

INSTALANDO NETBEANS IDE Y CREANDO EL “HOLA MUNDO”:

No tiene mucha dificultad instalar el ambiente de desarrollo, simplemente ejecutan el instalador y

siguen los pasos. Igualmente, para evitar problemas lo veremos paso a paso. Inicialmente tenemos

esta ventana:

Luego de que cargue nos aparece esta:

Allí verán qué es lo van a instalar. En este caso se lista todo lo que vimos hoy porque yo bajé el paquete completo. Si le dan en Personalizar podrán elegir qué instalar y qué no. Damos en Siguiente:

Page 4: Curso Java - Foro Lospillaos

Nos aparece el hermoso contrato de licencia que todos morimos por leer detenidamente sin perdernos una sola palabra. No creo que exista alguien en el ancho mundo que solo de clic en Acepto los términos del acuerdo de licencia y de Siguiente si leer absolutamente nada ¿o sí? ;)

Dependiendo de los componentes elegidos para instalar podrían aparecer más hermosos contratos así que estaremos felices de tener tanto que leer.

Llegamos a esta ventana:

Aquí tienen dos cuadros, uno para elegir donde instalar NetBeanas (les recomiendo que dejen el que viene por defecto) y otro para indicarle a NetBeans donde encontrar el JDK. En mi caso aparece ya por defecto porque la

Page 5: Curso Java - Foro Lospillaos

variable PATH está bien configurada, sin embargo, si no les aparece le dan clic en Examinar y buscan ustedes a mano el lugar donde esta su JDK y listo, NetBeans lo detecta y no nos hace problema. Damos clic en Siguiente. Dependiendo de las opciones elegidas para instalar podría aparecernos alguna otra ventana para elegir donde instalar los otros componentes.

Se nos muestra un resumen de lo que instalaremos. La imagen de ustedes puede diferir en función de lo que hayan seleccionado para instalar. Si todo está bien le dan clic a Instalar y esperan pacientemente que se cargue todo. Si instalan el paquete completo realmente puede demorar, no importa que tan potente sea su equipo. No desesperen, la instalación configura muchas cosas, de modo que déjenla terminar tranquilamente.

Les recomiendo que vayan creando una carpeta donde colocar sus proyectos Java. Con este IDE no tienen problemas de rutas ni de nombres de directorios. Es moderno así que pueden tener espacios y demás, ahora sí, bienvenidos al siglo 21 jejeje.

-------------------------------------------------------------------------------------

El clásico Hola Mundo:

Como era de esperarse haremos nuestro Hola Mundo en Java. Ya deben saber que la función de crear un programa tan tonto es chocar contra el lenguaje nuevo y contra el ambiente de desarrollo, así que vamos a ello. Al abrir el IDE nos aparece la ventana de carga:

Page 6: Curso Java - Foro Lospillaos

Luego visualizamos la interfaz gráfica de NetBeans con la Página de Inicio:

Les recomiendo que toqueteen esta página y exploren, hay varias cosas interesantes. Si no quieren verla más cada vez que abren el IDE desmarquen la opción Mostrar al Inicio.

Bien, creemos nuestro primer proyecto. Al igual que en Modula, Java funciona con proyectos, así que vamos a Archivo --> Proyecto Nuevo:

Debemos elegir dos cosas: Categoría y Proyecto. Las categorías disponibles dependerán de lo que hayan instalado. Lo que a mí me interesa ahora es Java Estándar así que elegimos categoría Java y luego Java Application.

Las Java Application son aplicaciones Java comunes, es decir, programas de escritorio. Damos en Siguiente:

Page 7: Curso Java - Foro Lospillaos

Debemos darle un nombre al proyecto. En mi caso escribo HolaMundo (no debe contener espacios). Luego elegimos la ubicación. NetBeans crea una ubicación por defecto que si les gusta pueden dejarla. Dentro de dicha ubicación crea automáticamente una carpeta con el nombre del proyecto para guardar todos sus archivos.

Por defecto está marcada la opción Crear clase principal. Por ahora desmárquenla. Den clic en Terminar.

Tras eso NetBeans crea el proyecto y nos muestra esta ventana:

Page 8: Curso Java - Foro Lospillaos

A la izquierda tenemos un panel con tres pestañas:

• Proyectos: NetBeans nos muestra todos los proyectos que tenemos creados, como ahora solo tenemos uno es el único que podemos visualizar de momento. Ya tendremos más.

• Archivos: Nos permite visualizar todos los archivos que componen a nuestro proyecto. • Prestaciones: Son herramientas que amplían un proyecto, como por ejemplo, conexión a base de

datos. De momento no lo usaremos.

Si en la pestaña Proyecto hacemos clic en el símbolo de más (+) de un proyecto se nos despliega mucho sobre el contenido del mismo. Aprenderemos a usar esto poco a poco.

En Modula teníamos módulos que conformaban a nuestros programas, cada cual estaba conformado (excepto el módulo principal) por un archivo de definición DEF y uno de implementación MOD; estos módulos podrían representar eventualmente a algún tipo de objeto. En Java los módulos serán llamados Clases. Por suerte no tendremos dos tipos de archivos diferentes, sino que cada clase tendrá un único archivo. Al igual que en Modula teníamos un módulo principal, en Java tendremos una clase principal que será la que iniciará al programa.

De esta manera, lo que debemos hacer ahora es crear la clase principal de nuestro programa. Tenemos dos formas de hacerlo:

Vamos al menú Archivo --> Archivo Nuevo o bien presionamos el botón Archivo Nuevo de la barra de herramientas (acceso rápido CTRL + N). Elegimos la categoría Java y el tipo de archivo Java Class (Clase Java). Damos clic en Siguiente y luego le damos un nombre a la clase (no puede contener espacios). No importa el nombre que le demos. Yo le puse HolaMundo a la mía pero por costumbre. Damos clic en Terminar y tendremos algo como esto:

Como ven a la izquierda ahora podemos ver la nueva clase (archivo .java) agregada al proyecto. A la derecha vemos una pestaña con el nombre de la clase y la opción Source (fuente) marcada. NetBeans ya nos genera algo de código fuente en la clase. Lo que está en gris son comentarios (ya hablaremos de ellos luego porque Java tiene tres tipos de comentarios y aquí ya tenemos dos).

Borren los comentarios.

Page 9: Curso Java - Foro Lospillaos

• La otra forma es hacer clic derecho sobre el ícono del proyecto (la tazita de café roja), eligen Nuevo --> Java Class. Los demás pasos son iguales que para la manera anterior.

Veamos el código fuente que tenemos:

Código:

public class HolaMundo { }

Para empezar NetBeans pinta en azul las palabras reservadas del lenguaje. Allí tenemos:

• public: Indica que lo que va a ser declarado luego es de acceso público. Lo veremos más adelante, por ahora simplemente saben que tiene que ir.

• class: Indica que lo que estamos declarando es una clase. En Modula usabamos la palabra MODULE. Las clases siempre se declaran con esta palabra.

Luego de la palabra class va el nombre de la clase, al igual que en Modula luego de la palabra MODULE iba el nombre del módulo. El nombre de la clase es un identificador y por tanto cumple las mismas condiciones que los identificadores de Pascal y Modula excepto porque estos sí pueden llevar tildes (acentos) y la letra ñ. Ahora ya no tendremos que escribir el identificador AÑO como ANIO.

En Pascal el programa estaba escrito dentro de los bloques BEGIN y END y en Modula el módulo principal llevaba el bloque BEGIN/END. En Java nos olvidamos de las palabras BEGIN y END y las sustituimos por las llaves { y } respectivamente. De este modo, en el ejemplo, la llave { indica el inicio de la clase y la llave } indica el final de la misma. Lo que tenemos entonces allí ahora es una clase pública que se llama HolaMundo y está vacía porque no tiene código ninguno dentro de las llaves.

Escriban a mano entonces dentro de las llaves este código:

Código:

public static void main(String[] args){     }

Como verán NetBeans va corrigiendo sintaxis en tiempo real. Además, cuando escribimos la llave { y damos enter, NetBeans nos agrega la llave de cierre } ya indentada y todo. Otra cosa útil es que si nos paramos en una llave de apertura el IDE nos pinta en amarillo cuál es la que la cierra y viceversa. Lo mismo con los paréntesis y todo tipo de símbolo de apertura y cierre.

¿Qué es eso que acabamos de escribir? De momento les digo que es un procedimiento que se llama main (principal en inglés). Todo programa Java tiene una sola clase principal (al igual que los programas en Modula tenían un solo módulo principal). La clase principal es la única que tiene el procedimiento main que acabamos de escribir. Justamente eso es lo que la marca como clase principal. De momento no me detendré a explicar mucho más de este procedimiento, asuman que es así y a medida que avancemos todo se irá viendo claramente.

Algo importante es que el procedimiento también tiene llave de apertura y cierre. En Pascal y Modula llevaban un bloque BEGIN/END.

Bien, dentro de este procedimiento escribiremos el código:

Código:

System.out.println("Hola Mundo");

Esto último es una típica sentencia de Java. Como ven termina en punto y coma (;). Al igual que en Pascal y

Page 10: Curso Java - Foro Lospillaos

Modula, el símbolo de punto y coma tiene la función de separador, es decir, es el que separa una sentencia (instrucción) de otra. Las llaves de cierre no llevan punto y coma al final.

Antes de pasar al detalle de lo que significan estas palabras, veamos el código completo:

Código:

public class HolaMundo {     public static void main(String[] args){         System.out.println("Hola Mundo");     } }

Ahora van al menú Ejecutar --> Limpiar y generar Main Project. Luego van a Ejecutar --> Ejecutar Main Project. El IDE les pedirá que indiquen cuál es la clase principal del proyecto. Seleccionen la suya y den Aceptar.

Tendrán esta pantalla:

Verán que debajo apareció la pestaña Salida – HolaMundo (run). Esa es la salida de la consola del IDE, es decir, lo que antes veían en una pantalla negra con letras blancas horribles, ahora lo ven en esta pantalla dentro del IDE. Como ven, apareció el mensaje Hola Mundo.

Las opciones del menú Ejecutar las tienen también en la barra de herramientas.

Noten también que ahora en la pestaña Proyectos apareció un ícono verde de Play (reproducir) en el ícono de la clase que tenemos. Eso indica que ahora NetBeans la reconoce como clase principal y que es desde ella que ejecutará el programa. Esto lo veremos enseguida; primero analicemos un poquito más lo que tenemos en nuestro código:

Page 11: Curso Java - Foro Lospillaos

• Una declaración de clase:

Código:

public class HolaMundo

Como ya dije, en Java los programas se organizan en clases y no en módulos como sucedía en Modula 2. Las clases siempre se declaran con la palabra reservada class y luego un identificador. Así, la clase HolaMundo podía haber sido declarada como

Código:

class HolaMundo

El modificador de acceso public indica además que la clase declarada es pública. Por ahora esto lo dejamos en el aire y simplemente nos limitamos a colocarlo.

Las clases tienen un bloque de código fuente delimitado por la llave de apertura { y la de cierre }.

• Dentro del bloque de la clase HolaMundo tenemos un procedimiento llamado main cuyo encabezado es

Código:

public static void main(String[] args)

La declaración de subprogramas (procedimientos y funciones) en Java la veremos más adelante. Por ahora sepan que esto es un procedimiento y nada más. Lo destacable de este procedimiento es que se llama main y solo puede haber un procedimiento llamado main en todo el programa sin importar cuantas clases existan, es decir, solo una clase puede tener el procedimiento main (tenemos algunas excepciones pero las veremos luego). La clase que contiene a este procedimiento es la clase principal del programa. Cuando ejecutamos nuestra aplicación la ejecución comenzará por el procedimiento main.

NetBeans busca en todas las clases de nuestro programa para detectar cual es la que contiene al procedimiento main y así designarla como clase principal (main class). Por eso en un principio nos preguntó cuál era la clase principal. Una vez designada NetBeans no volverá a preguntarnos, simplemente correrá el programa desde la clase designada como principal.

Una vez detectada solo damos clic en el botón Ejecutar Main Project de la barra de herramientas y ya, nuestro programa correrá tranquilamente.

Si han puesto atención a lo que escribieron habrán visto que NetBeans ha puesto en letra cursiva el identificador main. Ya debería estar claro que es por su importancia en la programación en Java.

Un procedimiento como este declarado en Modula sería:

Código:

PROCEDURE main(args: ARRAY OF TipoString);

Donde TipoString está declarado así:

Page 12: Curso Java - Foro Lospillaos

Código:

TYPE TipoString= ARRAY[1..N] OF CHAR;

Verán que el argumento es un arreglo de strings.

• Dentro del bloque del procedimiento main tenemos:

Código:

System.out.println("Hola Mundo");

En Java la salida estándar es System.out. En realidad System es una clase ya creada en Java perteneciente al paquete java.lang (hablaremos de paquetes mucho más adelante). Esta clase tiene operaciones que nos permiten realizar tareas con el sistema, como por ejemplo, mostrar texto en consola con out, que es una variable. Todo esto ahora es super confuso y complejo. Lo importante es que System.out representa la salida estándar en Java y que con esto tenemos los procedimientos println y print tal como si fueran WriteLn y Write en Pascal respectivamente.

El procedimiento println recibe datos como argumentos y los muestra en pantalla. En este caso hemos pasado un literal (texto entre comillas), pero bien puede ser una variable, un número, etc; tal como sucedía con Write y WriteLn en Pascal aunque aquellos podían recibir varios argumentos separados por comas, pero print y println no.

Espero entonces que quede claro que print imprime los datos y deja el cursor justo al final de la línea en que imprimió y println deja el cursor una línea más abajo, es decir, imprime un fin de línea luego de los datos.

Si se fijan a la derecha del menú Ayuda de NetBeans tienen un cuadro de búsqueda. Escriban System allí y de las opciones que les aparecen elijan System (java.lang). Verán que abrirán la clase System y tendrán todo su código fuente disponible, absolutamente todo y con comentarios. Así ustedes podrán ver cualquier clase de Java ya que como dije antes este lenguaje es de código abierto.

Continuaremos trabajando con esto en la lección que sigue. Verán que poco a poco Java se irá mostrando super sencillo. Al principio hay cosas que cuestan pero es, como siempre ha sido, solo acostumbrarse jeje.

NOTAS:

• Deberían haber notado ya que Java es sensible a mayúsculas y minúsculas (case sensitive) tal como lo era Modula2.

• El IDE NetBeans está totalmente programado en Java, así que tienen un gran ejemplo de lo que se puede lograr ¿no?

Page 13: Curso Java - Foro Lospillaos

LECCIÓN 63: SALIDA Y ENTRADA ESTÁNDAR EN JAVA.

SALIDA ESTÁNDAR BÁSICA

Hemos visto el clásico “Hola mundo” en Java y con él se nos han venido encima un montón de cosas. Además da la sensación de que eso de main es complicado y que el System.out también. ¿Por qué no hay un simple WriteString o WriteLn y ya? Además hay un montón de palabras raras que todavía no sabemos que son: public, static, void… Bien, todo se irá aclarando de a poco a medida que avancemos. Por el momento tendremos interrogantes que se quedarán colgadas porque no tengo forma de explicarlas sin irme a temas más avanzados. Es por este motivo que no pasé de Pascal a Java directamente.

Bien, vimos que los programas en Java en vez de módulos tienen clases. Las clases no tienen archivos DEF ni MOD sino que se crean en un archivo CLASS que por suerte NetBeans lo hace solito. Todo el código fuente está en un solo archivo así que nos olvidamos de eso de tener un archivo de definición y otro de implementación, todo está en un solo lugar para Java.

También vimos que, como un programa puede tener muchas clases, tiene que haber una que sea la principal para que el programa tenga un punto de partida al ejecutarse. Esta clase se diferenciará de las demás porque tendrá dentro de sí un procedimiento llamado main declarado sí o sí de esta manera:

Código:

1. public static void main(String[] args)

Dentro de este procedimiento irán las líneas de código fuente de ejecución del programa tal como sucedía en Modula 2 con el módulo principal.

Sabemos ya que al igual que en Modula, los literales de Strings van entre comillas dobles y que NetBeans los pinta en color naranja. La salida estándar está representada por System.out los cuales tienen para nosotros varios procedimientos y funciones útiles. De momento solo usaremos print y println.

En Pascal, cuando comenzamos con Write y WriteLn hicimos un ejemplo que mostraba el texto

Código:

Hice mi primer programa en Pascal. Logré el clásico “Hola Mundo”

El código fuente en Pascal para mostrar esta salida era:

Código:

1. WriteLn(‘Hice mi primer programa en Pascal.’);

2. Write(‘Logré el clásico “Hola Mundo”.’);

En Java sería así:

Código:

1. System.out.println(“Hice mi primer programa en Java.”);

2. System.out.print(“Logré el clásico Hola Mundo.”);

Como ven no hay diferencia. Lo único es que si ustedes corren el código Pascal y el código Java las salidas serán diferentes ya que el de Pascal mostrará las comillas en “Hola Mundo” y el de Java no lo hará. Es decir, tendremos esto en la salida de Pascal:

Page 14: Curso Java - Foro Lospillaos

Código:

Hice mi primer programa en Pascal. Logré el clásico “Hola Mundo”.

y esto en la salida de Java:

Código:

Hice mi primer programa en Java. Logré el clásico Hola Mundo.

Ya veremos cómo colocar esas comillas en la salida estándar de Java, ya que no es simplemente agregarlas. Esto es porque las comillas dobles en Java, al igual que en Modula 2, abren y cierran los literales de Strings, por eso si agregamos más comillas en nuestro argumento de print tendremos un error de sintaxis que NetBeans subrayará en rojo.

SECUENCIAS DE ESCAPE:

Justamente por el problema que señalé recién con las comillas y por otros tantos, además de lograr simplificarnos varias cosas, Java nos provee de ciertos caracteres especiales para utilizar en los literales de Strings. Como primer ejemplo veremos como lograr la misma salida anterior en una sola línea de código:

Código:

1. System.out.print(“Hice mi primer programa en Java.\nLogré el

clásico Hola Mundo.”);

Verán que solo hay un System.out.print. Sin embargo si ustedes corren ese programa saldrá el texto en dos líneas, tal como si hubiera usado println y print como en el ejemplo anterior. Si prestan atención, justo donde hay un salto de línea en la salida estándar tenemos en nuestro literal el símbolo \n. Este símbolo representa justamente el fin de línea. De este modo este código

Código:

1. System.out.println("Hola Mundo");

puede ser sustituido por

Código:

1. System.out.print("Hola Mundo\n");

La barra diagonal inversa (\) se conoce como carácter de escape. Esta barra indica a print y a println que se va a imprimir un carácter especial, de modo que dicho carácter va justo luego de la barra. En este caso, la n minúscula indica que lo que se quiere imprimir es un salto de línea. De esta manera, si yo quiero que salga en pantalla este texto:

Código:

He logrado crear mi primer programa en el lenguaje Java.

podemos hacerlo con éste código.

Page 15: Curso Java - Foro Lospillaos

Código:

1. System.out.println(“He logrado crear”);

2. System.out.println(“mi primer programa”);

3. System.out.println(“en el lenguaje Java.”);

o bien podemos hacerlo con este código

Código:

1. System.out.print(“He logrado crear\nmi primer programa\nen el

lenguaje Java.”);

Es importante que quede claro que cada vez que dentro de un literal escribimos \n imprimiremos un salto de línea.

Para imprimir las comillas dobles tenemos la secuencia de escape \”. De este modo para lograr aquella salida que queríamos fuera igual que en Pascal el código fuente sería:

Código:

1. System.out.println(“Hice mi primer programa en Java.”);

2. System.out.print(“Logré el clásico \”Hola Mundo\”.”);

Así, cada vez que usamos \” Java imprime comillas dobles (“) en pantalla.

Tenemos un total de cinco secuencias de escape:

• \n Nueva línea. Imprime un carácter de fin de línea, o sea, baja el cursor una línea. • \t Tabulación. Imprime una tabulación horizonal. • \r Retorno de carro. Vuelve el cursor al inicio de la línea actual. Todo lo que se imprima allí sobreescribirá a los caracteres que ya estaban impresos. • \\ Barra inversa. Imprime una barra inversa (\) en la salida. • \” Doble comilla. Imprime comillas dobles (“) en la salida.

ENTRADA ESTÁNDAR E INTRODUCCIÓN A LAS VARIABLES EN JAVA: Hemos visto la salida estándar en Java, lo cual, si lo analizan un poco, no es más que lo que ya usábamos en Pascal y es además bastante más simple que en Modula 2 ya que no tenemos que importar nada y podemos imprimir todo en una sola línea de código. Ahora bien, la entrada estándar no es algo tan sencillo porque Java no nos provee (dada su forma de funcionar) de un procedimiento o función que directamente lea lo que hemos escrito en consola, es decir, no tenemos un READ o READLN.

¿Cómo logramos leer algo de la entrada estándar entonces? Pues bien, tenemos que importarnos una clase llamada Scanner y crearnos un objeto de esa clase. Como ven, ya tenemos programación orientada a objetos solo para lograr una lectura estándar. Otro motivo para haber hecho un pasaje por Modula antes de llegar a Java. Igualmente por ahora no se compliquen, solo nos limitaremos a ver cómo funciona y cómo lograr obtener lecturas desde el teclado sin mayores complicaciones ¿ok?

Esto seguirá generando esa sensación de que Java nos complica todo, pero no es así, es su funcionamiento, que una vez comprendido será super intuitivo. Haremos un programa simple que pida el nombre del usuario y luego lo salude, tal como hicimos en Pascal. Esto nos llevará a tener variables. Veamos el código fuente:

Page 16: Curso Java - Foro Lospillaos

Código:

1. import java.util.Scanner;

2.

3. public class HolaMundo {

4. public static void main(String[] args){

5. //Declaración de variables.

6. Scanner entradaEstandar= new Scanner(System.in); //Lector de la entrada.

7. String nombre; //Variable que almacenará lo leído.

8.

9. System.out.print("Escribe tu nombre: "); //Un mensaje al usuario.

10. nombre= entradaEstandar.nextLine(); //Leemos lo ingresado.

11.

12. System.out.print("Hola "); //Imprimimos un mensaje.

13. System.out.print(nombre); //Imprimimos el contenido de la variable entrada.

14. }//Fin del procedimiento main.

15. }//Fin de la clase HolaMundo.

Bueno, se ha complicado un poquito así que como siempre, veamos línea por línea lo que tenemos a fin de que no queden dudas de nada. Así que vamos por la línea 01 donde hay una importación. Como dije hoy necesitábamos usar la clase Scanner. En java las librerías constan de varias clases las cuales se agrupan en paquetes. Un paquete consta entonces de varias clases y subpaquetes. Bien, la clase Scanner está dentro de un paquete llamado util que está dentro de un paquete llamado java. Las importaciones en Java se hacen, al igual que en Modula, al inicio del código fuente antes de declarar la clase. Usamos la palabra reservada import para decir que queremos importar una clase o un paquete de clases. La declaración es entonces así

Código:

1. import nombreDelPaquete.nombreDelSubpaquete.nombreDelSubpaquete….nombreDeLaClase;

Como ven, lo que se hace es separar por puntos (no espacios) cada nombre de cada paquete hasta llegar a la clase. Como Scanner está en el paquete util el cual está dentro del paquete java, tenemos que escribir

Código:

1. import java.util.Scanner;

De momento solo deben saber eso, luego veremos como el IDE nos facilitará la vida con las importaciones, pero primero tienen que aprender a hacerlas ustedes a mano.

Sigamos. En la línea 03 tenemos la declaración de la clase HolaMundo. Como verán, usé la misma clase que ya teníamos solo porque no tenía ganas de hacer otro proyecto. En la línea 04 tenemos la declaración del procedimiento main. En la línea 05 tenemos un comentario de fin de línea. Estos comentarios los habíamos visto en Pascal y se abren con el mismo símbolo que en aquel lenguaje (//). Se cierran automáticamente con el fin de la línea en que se escriben. Como ven, el IDE pinta en gris los comentarios.

En la línea 06 aparece por primera vez la declaración de una variable, que encima no es de un tipo primitivo sino que es de tipo Scanner, es decir, es una variable del tipo de una clase (como si nosotros nos declaráramos una variable del tipo de un módulo en Modula 2), o sea que es una referencia a un objeto. No me concentraré en este hecho todavía porque no quiero llegar a la programación orientada a objetos en Java tan rápido, hay mucho por ver antes.

Page 17: Curso Java - Foro Lospillaos

En Pascal y en Modula 2, a la hora de declarar una variable primero escribíamos el nombre de la variable, luego dos puntos y luego el tipo de datos que almacenaría. En Java va primero el tipo de datos y luego el nombre de la variable sin poner dos puntos. Por ejemplo, en Pascal una variable nombre del tipo String se declararía así:

Código:

1. nombre: String;

En Modula 2 sería así:

Código:

1. nombre: ARRAY[1..N] OF CHAR;

En Java sería

Código:

1. String nombre;

Algo nuevo es que no necesitamos poner una palabra reservada para declarer variables en Java como sucedía en Pascal y en Modula donde teníamos que poner VAR y luego declarar las variables. Ahora podemos declararnos una variable en cualquier momento donde se nos antoje . Si vamos programando y nos damos cuenta que necesitamos tal o cual variable la declaramos en el momento y ya. No es prolijo, a pesar de que Java nos permite hacer eso, se suele declarar todas las variables al inicio del código para que este sea más legible por otras personas y por uno mismo.

Bien, me declaré una variable llamada entradaEstandar del tipo Scanner. Esta variable será la que nos devuelva los textos de ingresados por el usuario. En la misma línea donde está declarada entradaEstandar la he inicializado asignándole un valor por defecto mediante

Código:

1. new Scanner(System.in)

Esta asignación quedará colgada por ahora. Lo importante es que para poder obtener resultados de la entrada estándar debemos declararnos una variable Scanner tal como yo lo he hecho.

El símbolo de asignación en Pascal y Modula era (:=), ahora en Java es simplemente el (=).

En la líena 07 me declaro una variable llamada nombre del tipo String. En Java volvemos a tener el tipo String y nos olvidamos del ARRAY OF CHAR de Modula 2. Este tipo es casi como si fuera un tipo primitivo de Java aunque en realidad no lo es. Por el momento nosotros lo usaremos como un tipo primitivo ya que podemos hacerlo sin ningún problema. Luego en la línea 09 imprimimos un simple mensaje al usuario. La línea 10 es la que hace la lectura de la entrada estándar. Veámoslo de forma simple:

Scanner nos provee de una función llamada nextLine que no recibe argumentos y retorna un String que es justamente lo leído de la entrada estándar. La función nextLine lee toda la línea completa, como si fuera READLN. A diferencia de READ o READLN, donde poníamos la variable que recibiría los datos como argumento de estos procedimientos, nextLine lo retorna como función, por tanto tenemos que asignar ese retorno a la variable nombre. Es como si en Pascal en vez de hacer

Page 18: Curso Java - Foro Lospillaos

Código:

1. ReadLn(nombre);

hiciéramos

Código:

nombre:= ReadLn();

Sin embargo, nextLine al ser una operación de Scanner debe usarse mediante un objeto de esta clase (eso es parte de POO en Java y lo veremos luego). De este modo debo usar el objeto entradaEstandar para usar nexLine simplemente escribiendo entradaEstandar.nextLine().

Entonces, la línea 10 lo único que hace es asignar a nombre lo leído en la entrada estándar. La línea 12 simplemente muestra el mensaje Hola con un espacio al final y la línea 13 imprime el contenido de la variable nombre. Como ven, println y print puede recibir variables como argumentos para ser mostrados en pantalla tal como sucedía con WriteLn y Write de Pascal.

Las líneas 14 y 15 cierran los bloques de main y HolaMundo respectivamente con comentarios que lo aclaran. Dejar comentarios que aclaren qué cierra cada llave ayuda a mejorar el código, más allá de que NetBeans marca en amarillo las llaves que abren y cierran un bloque.

EL OPERADOR + EN LOS LITERALES: Las dos líneas finales que muestran el mensaje al usuario

Código:

1. System.out.print("Hola ");

2. System.out.print(nombre);

Podrían haberse sustituido con esta línea

Código:

1. System.out.print(“Hola “ + nombre);

Esto no era permitido en Pascal y mucho menos en Modula 2. Java nos permite utilizar el operador + en los literales y hace la unión automáticamente. En Pascal teníamos la salvedad de que un mismo procedimiento Write o WriteLn podía recibir varios argumentos separados por comas, pero esto en Java y Modula no es posible. De este modo Java nos provee una forma elegante de solucionarlo.

Si quisiéramos que el mensaje final fuera:

Código:

Hola [nombreIngresado]. Es un placer conocerte.

Tendríamos básicamente dos opciones:

• Escribimos este código:

Código:

Page 19: Curso Java - Foro Lospillaos

1. System.out.println(“Hola “);

2. System.out.println(nombre);

3. System.out.println(“. Es un placer conocerte”);

• Escribimos este código:

Código:

1. System.out.println(“Hola “ + nombre + “. Es un placer

conocerte.”);

Como verán, queda mucho más corto y más sencillo el código fuente. Así se podría escribir todo en una sola línea, no importa cuántos signos de + tengan que utilizar, cuantas variables hayan, cuantas veces usen cada variable. Pueden armar las frases que quieran.

Notas interesantes:

• Si ponemos el cursor sobre una variable, NetBeans pinta todas las partes del código donde dicha variable aparece. Además nos muestra en la barra vertical a la derecha de la pantalla todos los lugares de modo que si hacemos clic allí vamos directo a la parte del código que queremos.

• Si al escribir el nombre de la variable del tipo Scanner ponemos luego un punto, NetBeans nos muestra todas las operaciones disponibles detallando información al respecto. Podemos subir y bajar por todas ellas a fin de elegir la que necesitamos.

Page 20: Curso Java - Foro Lospillaos

LECCIÓN 64: EJEMPLO PRÁCTICO DE LECTURA: ÁREA DEL TRIÁNGULO.Vimos hasta ahora en Java un tipo primitivo de datos, el tipo String. Sabemos ya que para declarar una variable debemos primero poner el tipo y luego el nombre de la variable. Ahora veremos aquel programa que hicimos en Pascal para calcular el área y el perímetro del triángulo. Aquí veremos dos tipos primitivos más. Lo haremos en un proyecto nuevo llamado AreasYPerímetros.

Para crear un nuevo proyecto en NetBeans pueden hacer lo siguiente:

• Van a Archivo --> Proyecto Nuevo. • Presionan CTRL + SHIFT + N. • Presionan el botón Proyecto Nuevo de la barra de herramientas. • Hacen clic derecho sobre un espacio en blanco del área en que se muestran los proyectos (debajo de

la pestaña Proyectos) y eligen Proyecto Nuevo.

Con cualquiera de esas opciones tendrán la ventana que usamos al crear el HolaMundo. Pongan a su proyecto el nombre AreasYPerimetros. Desmarquen la opción Crear Main Class.

Ahora, debajo de la pestaña Proyectos, vemos que aparece el nuevo proyecto creado marcado en letra negrita. Esto es porque al momento de crearlo estaba marcada la casilla Set as Main Project (establecer como proyecto principal). Esta casilla está debajo de Crear Main Class.

¿Qué significa que un proyecto esté marcado como proyecto principal? Pues que al compilar y/o ejecutar estaremos ejecutando el proyecto principal establecido. De este modo si ustedes dan clic en el botón Ejecutar Main Project o bien presionan F6, no estarán corriendo HolaMundo aunque estén mirando su código fuente, sino que NetBeans intentará correr AreasYPerímetros y no podrá porque no tiene ninguna clase principal. Para cambiar el proyecto establecido como principal simplemente deben hacer clic derecho sobre su nombre y elegir la opción Establecer como Proyecto Principal (puede aparecer Set as Main Project). Con eso ya está. Igualmente ustedes pueden correr o compilar un proyecto sin establecerlo como proyecto principal; para ello hacen clic derecho sobre él y elijen Ejecutar (si es que quieren correrlo) o Limpiar y Construir (si solo quieren compilarlo). Creemos entonces la clase principal de nuestro proyecto AreasYPerimetros. Es usual colocar a la clase principal el mismo nombre que tiene el proyecto (tal como yo lo hice con HolaMundo). No es requerido, es decir que, si yo ahora le pongo a mi clase principal el nombre Abuela, el programa funcionará sin problemas (en Modula no era así), pero a la hora de leer el código fuente, sobre todo si hay muchas clases, se facilita encontrar la clase principal por el nombre. Más allá de eso, NetBeans nos marca con el ícono verde de Play la clase establecida como clase principal.

La ejecución de nuestro programa debe como quedar la que muestro a continuación. Pinto en azul lo que corresponde a la entrada ingresada por el usuario. Los datos ingresados serán números enteros.

Cita:

Bienvenid@ a Áreas y Perímetros. Calcularemos el área y el perímetro de: *Un triángulo. *Un rectángulo. *Una circunferencia.

Vamos con el área del triángulo. La base será el primer lado ingresado. Ingresa la medida de sus lados y su altura: 10 5 7 3

Lado a= 10 Lado b= 5 Lado c= 7 Altura= 3

Área= 15.0 Perímetro= 22

Veremos dos formas de hacer esto:

Page 21: Curso Java - Foro Lospillaos

• Usando una variable área y una variable perímetro para estos cálculos. • Realizando los cálculos directamente en println.

Código:

01 import java.util.Scanner; 02 03 public class AreasYPerimetros { 04     public static void main(String[] args){ 05         //Declaramos las variables a usar. 06         Scanner entradaEstandar= new Scanner(System.in); 07         int a, b, c, altura, perímetro; 08         double área; 09        10         /*Mostramos el mensaje inicial al usuario. Haré todo en una misma línea 11          * de salida para que se vallan acostumbrando. 12         */ 13         System.out.print("Bienvenid@ a Áreas y Perímetros.\n\n" 14                 + "Calcularemos el área y el perímetro de:\n\n" 15                 + "*Un triángulo.\n*Un rectángulo.\n*Una circunferencia.\n\n" 16                 + "Vamos con el área del triángulo.\nLa base será el primer lado" 17                 + " ingresado.\nIngresa la medida de sus lados y su altura: "); 18          19         //Leemos uno a uno los valores ingresados: 20         a= entradaEstandar.nextInt(); 21         b= entradaEstandar.nextInt(); 22         c= entradaEstandar.nextInt(); 23         altura= entradaEstandar.nextInt(); 24        25         /*Consumimos el fin de línea, tal como hacíamos con ReadLn en Pascal y 26          * con SkipLine en Modula 2. En Java es usar nextLine solo. 27          */ 28         entradaEstandar.nextLine(); 29          30         área= a*altura/2.0; 31         perímetro= a + b + c; 32          33         System.out.println("\nLado a= " + a + "\nLado b= " + b + "\nLado c= " + c 34                 + "\nAltura= " + altura + "\n\nÁrea= " + área + "\nPerímetro= " 35                 + perímetro); 36     }//Fin del procedimiento main. 37 }//Fin de la clase AreasYPerimetros.

Este código es apenas más complejo que lo que hemos venido viendo, pero no más complejo que lo que ustedes ya saben utilizar. Veamos las líneas importantes de este código nada más ya que hay mucho que ya he explicado.

Vamos entonces directo a la línea 07 donde tenemos una declaración de varias variables del tipo int, el cual es un tipo primitivo de Java y se corresponde con el tipo INTEGER de Pascal y Modula con la enorme diferencia de que admite valores mucho mayores (veremos esto luego). Como ya saben, en Java para declarar variables primero va el tipo de datos y luego la variable. Al igual que en los lenguajes anteriores, en Java podemos declarar varias variables de un mismo tipo separándolas por coma. Así, las variables del tipo int declaradas son a, b, c, altura y perímetro.

En la línea 08 tenemos otra declaración de variable para una llamada área del tipo primitivo double. Este tipo se corresponde con el tipo REAL de Modula y Pascal, salvo también que admite valores muchísimo mayores. Como verán, sigo usando la vieja práctica de declarar todas las variables al inicio del código. Por el momento siempre estoy haciendo las declaraciones de variables dentro del propio procedimiento main, es decir que son variables locales a él. Como por ahora siempre estaremos trabajando dentro de dicho procedimiento no nos complicaremos con variables globales ni mucho menos.

Entre las líneas 10 y 12 tenemos un bloque de comentarios multilínea. Este es el tipo de comentarios que usábamos en Modula el cual comenzaba con (* y cerraba *). En Pascal también se abrían y cerraban con dichos símbolos o bien con las llaves {}. En Java los comentarios multilínea se abren con /* y se cierran con */. Este es el segundo tipo de comentarios que posee Java y el segundo tipo de comentarios que ustedes conocen. Este

Page 22: Curso Java - Foro Lospillaos

lenguaje integra un nuevo tipo de cometarios conocidos como javadoc, pero los veremos más adelante.

Luego entre las líneas 13 y 17 tenemos una impresión en pantalla de todo el texto que se debe mostrar al usuario tal como lo describí en el ejemplo. Podría haber usado varios println para lograr la misma salida, sin embargo quiero que vean cómo podemos escribir una salida muy larga en un solo print o println uniendo los trozos de texto con signos de suma (+). Eso es lo más común en Java. Modula no nos permitía esto y Pascal tampoco. La facilidad que nos da la secuencia de escape \n es muy valorable, ahorramos mucho tiempo.

Ahora viene la parte en que leemos los datos. Esta vez no usé nexLine ya que no quería leer toda la línea completa y además no quería recibir algo de tipo String, sino que quería leer de a uno los números ingresados por el usuario. Para esto en vez de usar nexLine usamos nexInt, que justamente lee un entero (algo del tipo primitivo int) en la entrada y nos lo devuelve. No consume toda la línea, sino que lee un entero y luego deja el cursor justo adelante del siguiente espacio. Cabe destacar que para usar nextInt lo que el usuario ingresó debe ser justamente un número del tipo int, de lo contrario Java nos lanzará una excepción del tipo InputMismatchException que significa Excepción de falta de coincidencia en la entrada (veremos excepciones más adelante) y nos mostrará un mensaje como este en la salida de la consola:

Cita:

Exception in thread "main" java.util.InputMismatchException

at java.util.Scanner.throwFor(Scanner.java:840)

at java.util.Scanner.next(Scanner.java:1461)

at java.util.Scanner.nextInt(Scanner.java:2091)

at java.util.Scanner.nextInt(Scanner.java:2050)

at AreasYPerimetros.main(AreasYPerimetros.java:20)

Java Result: 1

GENERACIÓN CORRECTA (total time: 5 seconds)

Estos informes de errores nos ayudan mucho a la hora de detectar problemas. Lo que está en rojo indica, en cada renglón, el paquete, la clase y la operación en la que se ha producido el error separando cada dato por un punto porque justamente está indicando paquetes. Lo que está en azul es un enlace hacia la clase indicada en la línea exacta donde sucedió el problema (si hacemos clic en él nos lleva justo a donde se detectó el error). Esto hay que leerlo desde abajo hacia arriba (por un tema de herencia). Si se fijan, el último error indicado está en la clase AreasYPerimetros en la operación main, más explícitamente en la línea 20. Justo la línea 20 es donde se lee el primer entero y se le asigna el valor a la variable a. El problema fue que el usuario no ingresó algo del tipo int y por eso nuestro programa cayó. Luego el error nos lleva a la línea 2050 de la clase Scanner y así podemos navegar hasta la línea 840 de dicha clase que es donde se lanzó la excepción. De momento sabemos que el problema es el ingreso de datos y con eso nos basta para proseguir. Debajo de todo el informe indica GENERACIÓN CORRECTA ya que el programa compila bien y por tanto el archivo .class fue creado; el problema que hubo fue en tiempo de ejecución.

Hasta la línea 23 de nuestro código tenemos las asignaciones de los números ingresados por el usuario. Dichos números pueden ingresarse de a uno separando por espacios o bien presionando ENTER. Es como cuando utilizábamos READ en Pascal con una variable INTEGER para leer de a uno los enteros.

Al igual que sucedía en Pascal, tenemos que consumir el fin de línea luego de leer algo que no lo consume. Esto en aquel lenguaje lo hacíamos colocando un READLN solito. En Modula lo hacíamos con SkipLine. Pues en Java lo hacemos colocando nextLine solamente. Recuerden que las operaciones que estamos utilizando para leer son de la clase Scanner y por eso se hacen a travéz del objeto Scanner que nosotros nos creamos. En la línea 28 consumimos el fin de línea.

En la línea 30 tenemos una sentencia de asignación donde le damos a la variable área el valor de multiplicar la variable a por la variable altura y dividir esto entre 2. En Pascal o Modula esta asignación sería:

Código:

area:= a*altura/2.0;

En Java lo único que cambia es que el signo de asignación (:=) cambia por (=). Algo que cabe destacar es que

Page 23: Curso Java - Foro Lospillaos

podía haber puesto 2 en vez de 2.0. La diferencia es que uno es un número entero y el otro es un número real. En Pascal y Modula la operación / era estrictamente del tipo REAL. En Java eso no es así, al menos no en las versiones actuales. Si todos los operandos de la operación matemática son del tipo int pues Java transformará el resultado de la operación / a tipo int. Por ejemplo, sabemos que la variable área es del tipo double (casi equivalente al tipo REAL de Pascal y Modula) y que a y altura son del tipo int. Si yo hago aquella asignación de esta manera

Código:

área= a*altura/2;

estoy dejando todos los operandos del tipo int. Como no hay ninguno del tipo double Java hace la operación / retornando un int tal como si fuera DIV en Modula o Pacal. Luego asigna eso a la variable área; como esta es double Java transforma el resultado int a double agregando un 0 luego de la coma. El problema de esto es que perdemos precisión. Veamos un ejemplo:

Supongamos que:

• a= 7 • altura= 3

Si hacemos la operación de la segunda forma (todos int) tenemos que:

Código:

7*3/2= 10

Luego Java asignará el valor entero 10 a la variable área pero dejándolo como 10.0 para que sea double. Eso claramente está mal, aquella cuenta debe dar 10.5. Para que / funcione como división real debe haber algún real en los operandos, por eso pongo el 2 como 2.0. Resumiendo, en Pascal y Modula teníamos DIV para división entera y / para división REAL. En Java tenemos solo /, y esta funciona como división entera si todos los operandos son enteros y como división real si hay al menos un operando que del tipo real (double para Java).

Cabe destacar que el símbolo de multiplicación sigue siendo el viejo y querido asterisco (*).

En la línea 31 asignamos a la variable perímetro la suma de los lados del triángulo. En la línea 33 comienza el último println el cual en una sola instrucción imprime todo el mensaje final. A diferencia del mensaje inicial, donde todo lo que uníamos con el signo de suma (+) era del tipo String, ahora tenemos tanto String como números. Java nos permite realizar esta mezcla ya que el signo de suma (+) está sobrecargado, es decir, tiene dos funciones

• Sumar números matemáticamente. • Concatenar cadenas de caracteres.

Al encontrar Strings y números mezclados Java “transforma” los números a Strings y los concatena con las cadenas existentes formando las frases que queremos. De este modo, algo como esto

Código:

System.out.prinln(“El resultado es “ + resultado);

imprimirá, si por ejemplo la variable resultado vale 25, el mensaje:

Código:

El resultado es 25

Page 24: Curso Java - Foro Lospillaos

En Pascal podíamos hacer esto en una instrucción ya que Write y WriteLn permitían una lista variable de argumentos de diversos tipos. En Modula teníamos que utilizar múltiples instrucciones para imprimir los datos en función del tipo al que pertenecían. Java nos da una mayor soltura incluso que Pascal al sobrecargar el símbolo (+).

Hay un pequeño detalle con esto. El programa anterior se podía hacer sin utilizar las variables área y perímetro ya que podíamos realizar los cálculos directamente en la instrucción de salida:

Código:

System.out.println("\nLado a= " + a + "\nLado b= " + b + "\nLado c= " + c + "\nAltura= " + altura + "\n\nÁrea= " + a*altura/2.0 + "\nPerímetro= "+ (a+b+c));

Como ven he realizado los cálculos directamente en la instrucción de salida. La operación

Código:

a*altura/2.0

no es problema porque al tener símbolos de multiplicación (*) y/o división (/) y/o resta (-), Java detecta que es una operación matemática, la resuelve, y luego concatena el resultado a la cadena de salida. Sin embargo, la última operación que corresponde al cálculo del perímetro DEBE llevar los paréntesis para que le den precedencia. El tema es que como es una operación que solo tiene el símbolo (+) y en este caso dicho símbolo tiene dos funcionalidades (sumar números y concatenar cadenas de caracteres), Java necesita saber cuál de las dos funcionalidades queremos usar.

Supongamos esta instrucción:

Código:

System.out.println(“El perímetro es “ + a + b + c);

Si a=10, b= 11 y c= 13 el perímetro es 34. Sin embargo la salida que obtendrán es esta

Código:

El perímetro es 101113

¿Qué pasó? Pues como no era explícito, Java utilizó la funcionalidad de concatenar caracteres del operador (+) porque había un String (literal) en la instrucción de salida y pues en realidad tomó los números como si fueran Strings. Para solucionar eso la instrucción debería ser

Código:

System.out.println(“El perímetro es “ + (a + b + c));

Al tener los paréntesis, Java detecta la precedencia de la operación y, como todo lo que hay entre paréntesis corresponde a variables numéricas, realiza la cuenta matemática y luego concatena el resultado al String que está a la izquierda.

Con esto cerramos el ejemplo del área del triángulo no sin dejar un ejercicio:

NOTAS: El objeto del tipo Scanner tiene una operación next casi para cualquier tipo primitivo que queramos leer:

Page 25: Curso Java - Foro Lospillaos

• nextBoolean: Lee el siguiente booleano en la entrada estándar. • nextByte: Lee el siguiente valor del tipo byte. • nextDouble: Lee el siguiente número real. • nextFloat: Lee el siguiente número real. • nextInt: Lee el siguiente número entero. • nextLine: Devuelve un String con el contenido de toda la línea. • nextLong: Lee el siguiente número entero. • nextShort: Lee el siguiente número entero.

No tenemos una operación para leer datos del tipo char. Esto tiene una solución sencilla mediante el trabajo con el tipo String, pero la veremos más adelante.

Ejercicio: Completar el programa anterior para que además del área y el perímetro del triángulo calcule también el área y el perímetro de un rectángulo y de una circunferencia. Les dejo a continuación un ejemplo de ejecución, pintando en azul lo que corresponde a la entrada ingresada por el usuario:

Cita:

Bienvenid@ a Áreas y Perímetros.

Calcularemos el área y el perímetro de:

*Un triángulo. *Un rectángulo. *Una circunferencia.

Vamos con el área del triángulo. La base será el primer lado ingresado. Ingresa la medida de sus lados y su altura: 10 5 7 3

Lado a= 10 Lado b= 5 Lado c= 7 Altura= 3

Área= 15.0 Perímetro= 22

Ahora vamos con el área y el perímetro del rectángulo: Ingresa la medida de la base y la altura: 10 5

Base= 10 Altura= 5

Área= 50 Perímetro= 30

Solo falta la circunferencia. Ingresa la medida del radio: 10

Radio= 10

Área= 314 Perímetro= 62.8

Gracias por usar AreasYPerimetros.

NOTAS:

• El área de una circunferencia se calcula como r*r*PI donde r es el radio y PI es 3.14. De momento no usaremos constantes porque no lo he explicado.

• El perímetro de una circunferencia es d*PI donde d es el diámetro. • El diámetro de una circunferencia se calcula como r*2 donde r es el radio.

La salida de su programa debe ser idéntica a la mostrada en el ejemplo. Esto será una enorme práctica para ustedes con la cual comenzarán a manejar varios aspectos de Java.

Page 26: Curso Java - Foro Lospillaos

LECCIÓN 65: TIPOS, OPERADORES, DECLARACIONES Y SELECCIÓN

En esta lección veremos las palabras reservadas de Java, un poco más sobre declaración de variables añadiendo además las constantes, tipos primitivos y sus rangos de datos, operadores aritméticos y relacionales para así llegar a la selección, es decir, a los if y a algo parecido al CASE.

PALABRAS RESERVADAS Y TIPOS PRIMITIVOS DE JAVA

Al igual que cualquier lenguaje Java tiene sus propias palabras reservadas. Como estas tienen un significado propio para el lenguaje no pueden ser utilizadas como identificadores para nada que queramos usar, tal como variables, constantes, clases, operaciones, etc.

Les dejo un listado de las palabras reservadas que existen en Java hoy día simplemente para que lo tengan presente:

abstract default if private this

boolean do implements protected throw

break double import public throws

byte else instanceof return transient

case extends int short try

catch final interface static void

char finally long strictfp volatile

class float native super while

const for new switch

continue goto package synchronized

Asimismo tenemos también los tipos primitivos de datos de los cuales conocemos dos hasta ahora: int y double. Los tipos primitivos son aquellos tipos de datos predefinidos por el lenguaje. Estos datos se almacenan directamente en memoria ocupando un cierto espacio ya establecido. Normalmente estos tipos de datos refieren a números, caracteres y booleanos. Veamos entonces qué tipos de datos primitivos nos da Java para trabajar:

• boolean: El típico booleano. Puede valer true o false. Ocupa 1 bit de memoria. • char: Un carácter Unicode, como los que ya conocemos. Ocupan 16 bits de memoria. • byte: Un número entero con signo. Va desde -128 hasta 128. Ocupan 8 bits de memoria. • short: Un número entero con signo. Este tipo es idéntico al tipo INTEGER de Pascal y Modula ya que

tiene el mismo rango de valores y cada variable de este tipo ocupa también 16 bits de memoria. Va desde -32768 hasta 32767.

• int: Un número entero con signo. Va desde -2147483648 hasta 214748647. Ocupan 32 bits de memoria. Como ven, ya tenemos un rango mucho mayor que en Pascal o Modula.

• long: Un número entero con signo. Va desde -9223372036854775808 hasta 92233720368547707. Ocupan 64 bits de memoria. Un super rango numérico.

• float: Un número de coma flotante. Este tipo es idéntico al tipo REAL de Pascal o Modula. Tienen un rango comprendido entre +-3.40282347E+38 y +-1.40239846E-45. Tiene una precisión simple. Ocupa 32 bits de memoria.

• double: Un número de coma flotante con doble precisión. Va desde +-1.79769313486231570E+308 hasta +-4.94065645841246544E-324. Ocupan 64 bits de memoria.

Como ven, los tipos numéricos nos dan mayores rangos con los que trabajar respecto a los que teníamos antes con Pascal y Modula. Hay que tener cuidado con la compatibilidad de estos tipos, pero me gustaría que ustedes mismos hicieran pequeñas pruebas declarando variables de distintos tipos y asignen a unas los valores de otras.

Por ejemplo, si yo me declaro una variable llamada real del tipo double y otra llamada entero del tipo int, puedo hacer esto:

Page 27: Curso Java - Foro Lospillaos

Código:

real= entero;

Sin embargo, si lo hago a la inversa NetBeans subrayará en rojo la asignación y si posamos el cursor del mouse sobre ella veremos el mensaje:

Cita:

possible loss of precision

required: int

found: double

Tenemos una forma de que Java “vea” una variable double como int para poder hacer una asignación que en Pascal o Modula era simplemente incompatible. Esta forma se conoce como casteo, pero la veremos más adelante.

Algo a destacar es que el tipo String no aparece como tipo primitivo de datos y justamente es porque no lo es. Un String es una concatenación de caracteres, es decir que, un String es la unión de varios datos de tipo char, el cual sí es un dato primitivo.

OPERADORES ARITMÉTICOS DE JAVA

Como era de esperarse y además como ya vimos, Java tiene sus operadores aritméticos, es decir, los símbolos que nos sirven para realizar operaciones matemáticas. Estos por lo general son los mismos en casi todos los lenguajes, siempre con alguna salvedad propia. En Java no tenemos mucha diferencia de lo que eran los operadores matemáticos de Pascal y Modula excepto por DIV y MOD que ahora ya no existen con esas palabras. Les pido que lean estos detalles porque hay sutilezas importantes y luego preguntan cosas que están explicadas aquí ¿si?:

• + (Suma): Simplemente realiza la suma de sus operandos. • - (Resta): Simplemente realiza la del segundo operando al primer operando. • * (Producto o multiplicación): Realiza el producto de sus operandos. • / (División o cociente): Realiza la división de sus operandos. Esta operación funciona como división real (tal como en Pascal o Modula) si hay al menos un operando de tipo real (float y double en Java). Si ambos operandos son enteros (short, int y long en Java) esta operación funciona como si fuera la operación DIV de Pascal o Modula, es decir, división entera. • % (Módulo o resto): Esta operación equivale a MOD en Pascal o Modula.

En las operaciones aritméticas siempre pueden estar presentes los paréntesis para dar precedencia a una operación u otra, tal como siempre ha sido. No me detendré a explicar eso.

Veamos en Java aquel ejemplo de Pascal que dado un número de cuatro cifras lo desglosaba y mostraba el resultado de dichas cifras. Recordemos el código Pascal:

Código:

1 {El siguiente programa desglosará un número de cuatro cifras 2 en sus cuatro números distintos, uno por cada cifra y realizará 3 la suma entre ellas} 4 PROGRAM SumaCifras; 5 6 Var 7     numero: integer; //El valor que será leído. 8     c1, c2, c3, c4: integer;//Una variable para cada cifra.

Page 28: Curso Java - Foro Lospillaos

9 10 BEGIN 11    write('Ingresa un número de cuatro cifras: '); 12    readln(numero); //Leemos el número de 4 cifras. 13 14   (*Asignamos a cada variable el valor de la cifra que le corresponde*) 15   c1:= numero mod 10; 16   c2:= (numero mod 100) div 10; 17   c3:= (numero mod 1000) div 100; 18   c4:= numero div 1000; 19 20   //Mostramos el resultado al usuario. 21   write('El resultado de sumar ',c4,'+',c3,'+',c2,'+',c1,' es: ',c1+c2+c3+c4); 22 END.

Ahora veamos el código Java:

Código:

import java.util.Scanner;

/*El siguiente programa desglosará un número de cuatro cifras en sus cuatro números distintos, uno por cada cifra y realizará la suma entre ellas*/ public class EjemploMOD {     public static void main(String[] args){         Scanner entrada= new Scanner(System.in);         int numero, c1, c2, c3, c4;                 System.out.print("Ingresa un número de cuatro cifras: ");         numero= entrada.nextInt();                 c1= numero % 10;         c2= (numero % 100)/10;         c3= (numero % 1000) / 100;         c4= numero / 1000;                 System.out.println("El resultado de sumar " + c4 + "+" + c3 + "+" + c2 + "+" + c1 + " es " + (c1+c2+c3+c4));     }//Fin de main. }//Fin de la clase EjemploMOD.

El código es casi exacto al de Pascal y creo yo que muy fácil de comprender. Comparen ambos y saquen sus propias conclusiones.

DECLARACIÓN DE VARIABLES Y CONSTANTES. SELECCIÓN EN JAVA Ya hemos visto la declaración de variables en Java, solo nos queda un pequeño detalle acerca de esto y es que podemos declarar variables a la vez que las inicializamos (es lo que hacemos con la variable del tipo Scanner). También veremos como declarar constantes en Java para pasar luego a la selección, es decir, a los viejos y queridos if.

DECLARACIÓN DE VARIABLES CON INICIALIZACIÓN CONJUNTA: Como ya sabemos, las variables se declaran así:

Código:

TipoDeDatos identificadorVariable;

Podemos además declarar muchas variables del mismo tipo separadas por comas además de que Java nos permite declarar las variables por cualquier parte del código siempre que las declaremos antes de usarlas. Bien, como ya saben siempre que vamos a usar una variable para alguna operación y no sabemos qué valor tendrá ya que no lo leeremos de la entrada (por ejemplo un contador para iterar) debemos inicializarlas. Veamos un ejemplo donde me declaro una variable del tipo int llamada i y la inicializo en 0:

Código:

Page 29: Curso Java - Foro Lospillaos

int i; i= 0;

Bien, eso no tiene nada de nuevo, primero me declaré la variable y luego la inicialicé. Java también me permite hacer esto para simplificar el código:

Código:

int i=0;

Como ven he declara la variable y a la vez le he dado un valor inicial. Supongamos que quiero declarar muchas variables del tipo int y quiero inicializar algunas sí y otras no. Podemos hacer todo por separado o todo junto así:

Código:

int i=0, j=8, altura, base, suma= 0;

Java nos da una libertad total a la hora de declarar variables. Allí tenemos tres que han sido inicializadas y dos que no. No tenemos que respetar ningún orden ni mucho menos. Se suele declarar a las variables que no inicializamos por un lado, y por otro lado a las que sí para dejar el código más claro, es decir, algo como esto:

Código:

int i=0, j=8, suma= 0; int altrua, base;

Esto es muy relativo ya que se pueden agrupar las variables según el uso que se les dará. En fin, cada uno escribe sus programas como más le guste. Dejen buenos comentarios y ya.

Algo importante es que a veces suele ser necesario en Java inicializar variables del tipo String dada la soltura de este lenguaje para el trabajo con cadenas de caracteres. ¿Con qué valor inicializo un String? Pues a menos que fuese lo que necesitamos podemos inicializar un String con algún valor que elijamos, pero Java nos provee la posibilidad de inicializar un String con un valor nulo el cual es “”. Sí, el String nulo es abrir y cerrar comillas. Por ejemplo:

Código:

String palabra= “”;

NOTA: El tipo char de Java utiliza comillas simples (como los Strings de Pascal) y no dobles porque sino serían Strings. Ejemplo:

Código:

char letra= ‘A’;

DECLARACIÓN DE CONSTANTES: Como ya saben, las constantes son “variables” que no cambian de valor, por eso está mal llamarlas variables. En Pascal y Modula las declarábamos debajo de la palabra CONST. Como no variaban hacía falta inicializarlas en la misma declaración. Algo interesante es que no le asignábamos el tipo ya que este quedaba implícito en el valor que le dábamos a la constante.

En Java, al igual que no existe VAR tampoco existe CONST y al igual que con las variables podemos declarar las constantes en cualquier lado. Es necesario poner el tipo de datos que contendrá. La declaración de constantes es igual a la de variables solo que anteponemos la palabra reservada final:

Código:

Page 30: Curso Java - Foro Lospillaos

final int MI_CONSTANTE= 20;

La declaración de constantes en Java sigue siendo una declaración de variables y por tanto respeta las mismas reglas salvo la excepción de que a las constantes hay que inicializarlas sí o sí. De este modo podemos declarar muchas constantes en una sola línea tal como con las variables. En Java entonces las constantes pasan a ser variables finales.

Algo importante es que las constantes suelen declararse siempre en mayúscula. Es una convención, algo que ayuda dentro del código a distinguirlas de las variables. Java nos deja darles el nombre que queramos.

Como dato interesante es que podemos declarar constantes del tipo String, por ejemplo:

Código:

final String MI_CADENA= “Alguna cadena útil”;

Ejercicio: Transcriban este código Pascal a Java:

Código:

1 PROGRAM preciosIVA; 2 3 Const 4    iva= 23; 5 6 Var 7    harina, leche, azucar, sal, arroz: real;//Precios de los productos. 8    porcentaje: real; //Para calcular cuánto se debe sumar al precio. 9 10 BEGIN 11 12   //Mostramos mensajes al usuario y leemos los datos desde la entrada. 13   write('Precio HARINA : '); 14   readln(harina); 15   write('Precio LECHE : '); 16   readln(leche); 17   write('Precio AZUCAR : '); 18   readln(azucar); 19   write('Precio SAL : '); 20   readln(sal); 21   write('Precio ARRÓZ : '); 22   readln(arroz); 23 24   //Dejamos una línea en blanco. 25   writeln; 26 27   //Calculamos el porcentaje de IVA para harina. 28   porcentaje:= harina*iva/100; 29   //Mostramos el nuevo precio al usuario. 30   writeln('HARINA + IVA : ',harina+porcentaje:2:2); 31 32   //Calculamos el porcentaje de IVA para leche. 33   porcentaje:= leche*iva/100; 34   //Mostramos el nuevo precio al usuario. 35   writeln('LECHE + IVA : ',leche+porcentaje:2:2); 36 37   //Calculamos el porcentaje de IVA para azucar. 38   porcentaje:= azucar*iva/100; 39   //Mostramos el nuevo precio al usuario. 40   writeln('AZUCAR + IVA : ',azucar+porcentaje:2:2); 41 42   //Calculamos el porcentaje de IVA para sal. 43   porcentaje:= sal*iva/100; 44   //Mostramos el nuevo precio al usuario. 45   writeln('SAL + IVA : ',sal+porcentaje:2:2);

Page 31: Curso Java - Foro Lospillaos

46 47   //Calculamos el porcentaje de IVA para arroz. 48   porcentaje:= arroz*iva/100; 49   //Mostramos el nuevo precio al usuario. 50   writeln('ARROZ + IVA : ',arroz+porcentaje:2:2); 51 END.

En un programa muy sencillo.

OPERADORES RELACIONALES DE JAVA PARA EXPRESIONES BOOLEANAS:

Veamos como hacemos en Java para comparar números y demás:

Como ven solo han cambiado los operadores de igualdad y diferencia con respecto a los que teníamos en Pascal y Modula.

SELECCIÓN SIMPLE CON IF: En Java también tenemos el viejo y querido if, solo que ya no es IF…THEN como en Pascal o Modula, ahora es solo if. Su uso es así:

Código:

if (condición)     instrucción;

Ese es un if super sencillo, es decir, con una sola instrucción. Si hacen memoria, en Pascal podíamos tener IF con una sola instrucción al que no teníamos que ponerle BEGIN y END porque no hacía falta. En Java es igual, si el if tiene una sola instrucción podemos poner un bloque de llaves {} o no, es decir que aquel if podía haber sido

Código:

if (condición){       instrucción; }

De este modo, la forma general de un if en Java sería:

Código:

Page 32: Curso Java - Foro Lospillaos

if (condición){       Instrucción1;       Instrucción2;       . . .       InstrucciónN }

Algo super importante en Java es que la condición SIEMPRE va entre paréntesis, no hay excepción a eso, de otro modo tendrán un error de sintaxis.

Veamos un ejemplo sencillo:

Código:

import java.util.Scanner;

public class EjemploIF {     public static void main(String[] args){         Scanner entrada= new Scanner(System.in);         int n1, n2;                 System.out.print("Ingrese dos números enteros: ");                 n1= entrada.nextInt();         n2= entrada.nextInt();         entrada.nextLine();                 if(n1<n2)             System.out.println("El primero es menor que el segundo.");                 if(n1==n2)             System.out.println("Ambos números son iguales.");                 if(n1>n2)             System.out.println("El primero es mayor que el segundo.");     }//Fin de main. }//Fin de EjemploIF.

SELECCIÓN DOBLE CON IF…ELSE:

Como no podía ser de otro modo, si tenemos if tenemos else. Como ahora perdimos el THEN, en vez de IF…THEN e IF…THEN…ELSE tenemos if e if…else. La idea es exactamente la misma que en Pascal y Módula; dada una condición si esta se cumple hacemos lo que está en el bloque del if y sino lo que está en el else.

Cambien el código anterior por este:

Código:

if(n1<n2) System.out.println("El primero es menor que el segundo."); else if(n1==n2) System.out.println("Ambos números son iguales."); else        System.out.println("El primero es mayor que el segundo.");

Como verán, ya no tenemos más ELSIF. En caso de necesitar más de una instrucción deben usar llaves para crear bloques de instrucciones.

Page 33: Curso Java - Foro Lospillaos

Lo demás debería resultarles intuitivo. Prueben ustedes mismos.

OPERADORES LÓGICOS EN JAVA: También conocidos como operadores booleanos. Estos no son más que aquellos operadores que nos permiten componer condiciones, es decir, los ya conocidos NOT, OR y AND. Veamos cómo escribimos estos operadores en Java, recordando a la vez las viejas y queridas tablas de verdad.

Operador NOT lógico (!): Niega la condición que le sigue. Este operador se conoce como operador lógico de negación. En Pascal y Módula era NOT, ahora es !.

Operador AND condicional (&&): Ahora el AND se ha transformado &&. Este operador funciona exactamente igual que AND en Pascal o Modula, incluso evaluando por circuito corto. Si no lo recuerdan, AND evalúa dos condiciones y devuelve TRUE si ambas condiciones son verdaderas. Como la evaluación es por circuito corto si la primera condición es FALSE entonces ya no se evalúa la segunda porque sin importar su valor el resultado será FALSE. Veamos la tabla de verdad:

Operador OR condicional (||): Lo que antes era OR ahora se escribe con las dos barras verticales ||. Este operador funciona de forma idéntica que en Pascal o Modula, es decir, devuelve TRUE si al menos una de las condiciones es verdadera. Si la primera condición es TRUE ya no se evalúa la segunda porque sin importar su valor el resultado será TRUE; en contraparte, si la primera condición es FALSE entonces sí se evalúa la segunda.

Java introduce además tres operadores booleanos nuevos:

Operador AND lógico booleano (&): Idéntico al operador && con la salvedad de que evalúa por circuito completo, es decir, siempre se evalúan ambos operandos sin importar sus valores. La tabla de verdad es idéntica a la de &&. Puede resultar útil en algunas circunstancias, aunque no lo usaremos mucho.

Operador OR inclusivo lógico booleano (|):

El mismo caso. Este operador es idéntico al operador || salvo que evalúa siempre por circuito completo. La tabla de verdad es exactamente la misma.

Operador OR exclusivo lógico booleano (^):

Page 34: Curso Java - Foro Lospillaos

Ahora el operador ^ ya no se usará para punteros (porque Java no nos permite usarlos) sino que será un operador booleano. Este OR será TRUE sí y solo sí uno de los operandos es TRUE y el otro FALSE. Si ambos son TRUE o ambos son FALSE entonces devuelve FALSE. Veamos la tabla de verdad:

Este operador no tiene más remedio que evaluar por circuito completo.

¿Estamos de acuerdo en que podemos lograr este resultado componiendo || y && como lo hacíamos en Pascal y Modula?

SELECCIÓN MÚLTIPLE CON SWITCH: Ya no tenemos más el CASE…ELSE, ahora tenemos switch. Esta instrucción es prácticamente idéntica al CASE de Pascal o el de Modula excepto por algún detalle que ya veremos. Recordemos las declaraciones que usábamos con CASE hasta ahora:

En Pascal:

Código:

CASE variable OF Constante1: BEGIN             Instrucciones;              END;    . . .    ConstanteN: BEGIN             Instrucciones;          END;    ELSE       BEGIN          Instrucciones;       END; END;

Debemos recordar que en cada etiqueta (constante) podíamos omitir los bloques BEGIN/END si tenían solo una instrucción. La variable debía ser de un tipo ordinal, por tanto no servían Strings, números reales ni tipos definidos por nosotros mismos a menos que fueran enumerados.

En Modula 2:

Código:

CASE variable OF    Constante1:   Instruccion1;              . . .          InstrucciónX|    . . .    ConstanteN:   Instrucción1;          . . .          InstrucciónY|    ELSE          Instrucción1;          . . .          InstrucciónZ|

Page 35: Curso Java - Foro Lospillaos

END;

Igual que el CASE de Pascal salvo que ya no existen los bloques BEGIN/END. Para cada etiqueta las instrucciones se separaban por punto y coma salvo la última que se cerraba con la barra vertical |. Por lo demás funcionaba igual.

En ambos casos la etiqueta ELSE no era obligatoria sino que servía para hacer algo en caso de que la variable no tomara el valor de ninguna de las etiquetas. Podíamos omitir perfectamente el ELSE y en caso de que sucediera lo anteriormente dicho el CASE no hacía nada.

La instrucción switch de Java hereda un aspecto del CASE de Modula: tenemos “algo” que cierra todas las etiquetas. En Modula era la barra |, en Java será la palabra reservada break. Veamos la declaración genérica de switch y luego transformaremos un CASE para que quede claro:

Código:

switch (variable){    case etiqueta1: Instrucción(es);             break;    case etiqueta2: Intrucción(es);             break;    . . .

}

Como ven es casi lo mismo. La variable va entre paréntesis sí o sí. Antes de cada etiqueta debe ir la palabra case y luego los dos puntos. Por cada etiqueta podemos tener tantas instrucciones como queramos, incluyendo if y sentencias de repetición. Cada etiqueta debe (en realidad puede) finalizar con break.

Ejemplo:

Supongamos que la variable num es de tipo INTEGER en Pascal y Modula y de tipo int en Java:

CASE Pascal:

Código:

CASE num OF 1: WriteLn(‘El número es el 1.’);    2: Begin       WriteLn(‘El número es el 2.’);       Write(‘No me gusta mucho ese número.’);       End; 3: WriteLn(‘El tres también me gusta.’); END;

CASE Modula:

Código:

CASE num OF 1: WriteString(“El número es el 1.”)|    2: WriteString(“El número es el 2.”); WriteLn;       WriteString(“No me gusta mucho ese número.”)| 3: WriteString(“El tres también me gusta.”)|

Page 36: Curso Java - Foro Lospillaos

END;

Switch:

Código:

switch (num){    case 1: System.out.println(“El número es el 1.”); break;    case 2: System.out.println(“El número es el 2.”);         System.out.println(“No me gusta mucho ese número.”);         break;    case 3: System.out.println(“El tres también me gusta.”); break; }

¿Y el ELSE donde queda con switch? Pues switch en vez de ELSE tiene una instrucción llamada default que es exactamente lo mismo. Si la variable no toma el valor de ninguna de las etiquetas case entonces entramos en el default. Con el mismo ejemplo tendríamos:

Código:

switch (num){    case 1: System.out.println(“El número es el 1.”); break;    case 2: System.out.println(“El número es el 2.”);         System.out.println(“No me gusta mucho ese número.”);   break;    case 3: System.out.println(“El tres también me gusta.”); break;    default: System.out.println(“No se eligió ni 1, ni 2, ni 3.”);          System.out.println(“Default y ELSE son lo mismo.”);          break; }

¿Qué pasa si no usamos break?

Si prueban escribir las etiquetas de switch sin usar break verán que el código compila perfectamente. Bien, a diferencia de la instrucción CASE de Pascal o Modula, donde se ejecuta únicamente el código correspondiente a la etiqueta en la que entramos, switch nos da la posibilidad de ejecutar más de una etiqueta. La sentencia break hace que al llegar a ella salgamos directamente de switch, por tanto, poniendo break en todas las etiquetas tendremos un comportamiento idéntico al CASE. Ahora bien, si en una etiqueta no ponemos break, el código seguirá hacia abajo y entrará en la siguiente etiqueta ya sin comprobar si el valor se corresponde con la variable del encabezado porque de hecho no lo hará.

Si escribimos un switch donde ninguna etiqueta tenga break, entonces al entrar en una se ejecutarán todas las demás que están por debajo. Por ejemplo:

Código:

switch(num){    case 1: System.out.print(“1 “);    case 2: System.out.print(“2 “);    case 3: System.out.print(“3”); break;    default: System.out.println(“No se eligió nada entre 1 y 3.”); }

Si aquí num vale 1, entonces en la salida veremos 1 2 3 ya que entrará en la primera etiqueta, la ejecutará y como no tiene break entrará en la segunda la cual tampoco tiene break por lo cual entrará en la tercera que sí tiene break para evitar que el flujo siga de largo a la etiqueta default.

Page 37: Curso Java - Foro Lospillaos

Podemos elegir a qué etiquetas poner break y a cuáles no. Asimismo el orden de las etiqueta puede ser cualquiera, no tiene por qué ser ascendente como el del ejemplo ni mucho menos.

Este comportamiento puede resultar útil para algunos casos.

Ejercicio:

Escriban un programa que muestre un menú al usuario donde pueda elegir si quiere calcular el área y el perímetro de un triángulo, un rectángulo o una circunferencia. Si el usuario no elije una de las opciones dadas entonces se le mostrará un mensaje de error. Las opciones serán numéricas y se leerán como enteros Veamos un ejemplo:

Cita:

Bienvenido a Áreas y Perímetros.

Seleccione una opción:

1-- Calcular área y perímetro de un triángulo. 2-- Calcular área y perímetro de un rectángulo. 3-- Calcular área y perímetro de una circunferencia.

Selección: 3

Ingrese el radio de la circunferencia: 2 El área es: 12.56 El perímetro es: 12.56

Es un programa super sencillo, pero servirá mucho de práctica para afianzar Java y dejar de lado los viejos vicios arraigados de Pascal y Modula.

Precio de IGV

Código:

 import java.util.Scanner;

                        public class preciosIVA {   public static void main(String[] args){         Scanner Entrada= new Scanner(System.in);       double harina,leche,azucar,sal,arroz, porcentaje ;       final int iva=23;             System.out.print("Precio HARINA :");       harina= Entrada.nextDouble();             System.out.print("\nPrecio LECHE :");

Page 38: Curso Java - Foro Lospillaos

      leche= Entrada.nextDouble();             System.out.print("\nPrecio AZUCAR :");       azucar= Entrada.nextDouble();                     System.out.print("\nPrecio SAL :");       sal= Entrada.nextDouble();             System.out.print("\nPrecio ARROZ :");       arroz= Entrada.nextDouble();             porcentaje=harina*iva/100;       System.out.print("\nHARINA + IVA :" + (harina+porcentaje));             porcentaje=leche*iva/100;       System.out.print("\nLECHE + IVA :" + (leche+porcentaje));             porcentaje=azucar*iva/100;       System.out.print("\nAZUCAR + IVA :" + (azucar+porcentaje));             porcentaje=sal*iva/100;       System.out.print("\nSAL + IVA :" + (sal+porcentaje));             porcentaje=arroz*iva/100;       System.out.print("\nARROZ + IVA :" + (arroz+porcentaje));             }  }

Ejercicio que tiene que ver con switch xd

Código:

import java.util.Scanner;

public class AreasyPerimetros {

public static void main(String[] args){      Scanner entradaEstandar= new Scanner(System.in);    int a,b,c,altura,perimetro,opcion;    double area,per;        System.out.print("Bienvenid@ a Areas y Perimetros.\n\n" + "Elige una Opcion:\n\n"                      + "1.Un triangulo. \n2.Un rectangulo.\n3.Una circunferencia\n\n"                      + "\n\nSeleccion:"  );    opcion=entradaEstandar.nextInt();                                         switch(opcion){           case 1: System.out.print("\n\nVamos con el area del triangulo.\nLa base sera el primer lado ingresado \nIngresa la medida de sus lados y su altura:"                   );       a= entradaEstandar.nextInt();       b= entradaEstandar.nextInt();       c= entradaEstandar.nextInt();       altura= entradaEstandar.nextInt();                                   entradaEstandar.nextLine();       System.out.print("\nLado a=" + a + "\nLado b=" + b + "\nLado c=" + c               + "\nAltura=" + altura);                   area= a*altura/2.0;       perimetro= a+b+c;       entradaEstandar.nextLine();

Page 39: Curso Java - Foro Lospillaos

      System.out.print("\nArea= "+ area + "\nPerimetro=" + perimetro); break;                         case 2: System.out.print("\n\nVamos con el area y el perimetro del rectangulo."               + "\nIngresa la medida de la base y altura: "                    );             a= entradaEstandar.nextInt();       b= entradaEstandar.nextInt();             System.out.print("\n\nBase=" + a + "\nAltura=" + b);             area=a*b;       perimetro=2*(a+b);             System.out.print("\n\nArea="+ area + "\nperimetro=" + perimetro); break;                     case 3: System.out.print("\n\nVamos con la circunferencia.\nIngresa la medida del radio: ");       a= entradaEstandar.nextInt();             area=a*a*3.14;       per= a*2*3.14;             System.out.print("\n\nRadio=" + a + "\n\nArea=" + area +"\nPerimetro=" + per);             break;                                   }                      

}   

}

LECCIÓN 66: REPETICIÓN ITERATIVA EN JAVA - TIPOS A DEFINIR.REPETICIÓN ITERATIVAJava tiene las mismas estructuras de repetición iterativa que Pascal y Modula. Hay alguna diferencia mínima que veremos en detalle. Tenemos entonces algo como el FOR, algo como el WHILE y algo parecido al REPEAT. Vallamos una a una:

SECUENCIA DE REPETICIÓN FOR: Como ya sabemos de sobra la sentencia for realiza una repetición iterativa que no depende de una condición sino que depende de un contador. De este modo decimos que for itera un número de veces predefinido, el cual puede estar dado por un valor literal, una constante, una variable, una expresión matemática (no recomendado), etc.

En Pascal o Modula la instrucción for utilizaba una variable de control previamente definida la cual era inicializada en el propio encabezado del for. Por ejemplo, sea i una variable entera:

Código:

FOR i:= 1 TO n DO

La variable de control (en este caso i) debía estar definida previamente. Bien, en Java la sentencia for tiene un encabezado más complejo. Lo escribiré de forma genérica y luego veremos ejemplos:

Page 40: Curso Java - Foro Lospillaos

Código:

for ( variable ; condición de fin ; incremento o decremento)

Veamos un ejemplo de un FOR en Modula y luego lo llevaremos a Java para que se entienda:

Código:

FOR i:= 1 TO 10 DO    WriteString(“*”); END;

Estamos de acuerdo en que este FOR imprime 10 asteriscos ¿verdad? Bien, veámoslo en Java:

Código:

for (i = 1; i<=10 ; i= i + 1)    System.out.print(“*”);

Como ven el encabezado del for tiene tres argumentos que se separan por punto y coma. El primero indica la variable de control a utilizar y con qué valor se inicializa. El segundo argumento indica la condición de fin del for (sí, el for de Java tiene condición). El tercer argumento indica el aumento de la variable de control o bien, el decremento de la misma. En este caso aumentamos i en 1, pero podría haber sido 2 o más, depende de la necesidad.

La asignación de acumulación es ya bien conocida por ustedes, es decir que algo como i= i + 1 no debería resultarles extraño. Java sabe que es usual hacer eso y por tanto nos provee de esta forma de escribirlo:

Código:

i++;

Esa instrucción aumenta i en 1, idéntica a hacer

Código:

i= i + 1;

Veremos más de esto más adelante. Lo importante es que usándolo el encabezado del for quedaría así:

Código:

for (i = 1; i<=10 ; i++)

Si ustedes buscan información del for de Java en Google lo verán siempre de esta forma.

Como el for del ejemplo tiene una única instrucción puedo elegir si poner llaves o no, pero cuando tiene más de una instrucción sí o sí hay que poner llaves:

Código:

for (i = 1; i<=10 ; i++){    System.out.print(“*”);    Sistem.out.println(); }

Este for da una salida idéntica al anterior.

Page 41: Curso Java - Foro Lospillaos

El último detalle nuevo que tenemos para el for en Java es que podemos declarar la variable de control en el mismo for, lo cual es lo más habitual. Quedaría así:

Código:

for (int i= 1; i<=10 ; i++)       System.out.print(“*”);

La única restricción para este uso es que la variable declarada dentro del for no debe estar declarada antes, de otro modo no tendría sentido “redeclararla”. Asimismo, la variable declarada en el for no será visible fuera de él (como si fuera local), por tanto, si se quiere usar luego sí debemos declararla.

REPETICIÓN CONDICIONAL CON WHILE: En Java tenemos el viejo y querido while y por suerte funciona idéntico al WHILE de Pascal y Modula. Obviamente la declaración cambia ya que no es WHILE…DO, solo es while:

Cita:

while(condición) instrucción;

Cita:

while(condición){ instrucción; }

Allí tienen dos ejemplos de while con una sola instrucción. Como ya debería ser natural, en Java siempre que tenemos una sola instrucción podemos optar por no poner las llaves de cierre y apertura al igual que en Pascal podíamos optar por no poner BEGIN y END. La forma general de un while entonces es:

Código:

while (condición){       instrucción1;       instrucción2;       . . .       instrucción; }

Debería ser obvio que la condición puede ser una condición compuesta por operadores NOT, AND, OR, etc. Debe estar siempre entre paréntesis.

No me detendré más con esta instrucción porque no tiene caso, es lo que ya conocen.

REPETICIÓN CONDICIONAL CON DO…WHILE: Como dije antes, esta sería la forma que Java le da al REPEAT…UNTIL que ya conocemos. Esta instrucción igualmente difiere un poco con la de Pascal y Modula por una sutileza. Veamos su declaración:

Código:

do{    instrucciones; }while (condición);

Primero vuelvo a aclarar que si hay una sola instrucción podemos omitir las llaves (no lo recomiendo). Bien, como se darán cuenta enseguida, este bloque chequea la condición al final y no al inicio como while, de modo que al igual que REPEAT se ejecutará al menos una vez. El tema es que REPEAT…UNTIL es como decir “Repite hasta que…” y DO…WHILE es “Haz mientras que…”.

Mientras que REPEAT tenía la condición inversa al WHILE, ahora en Java tanto while como do…while tienen la misma condición. Veamos ejemplos sencillos:

Page 42: Curso Java - Foro Lospillaos

Como acabo de decir, la condición en Java siempre es la misma tanto para while como para do…while. Esto no es menor ya que de este modo la única diferencia entre una estructura y otra es que while puede no ejecutarse nunca y do…while se ejecuta siempre al menos una vez.

Ejercicio: Realicen el programa Adivinador propuesto en Pascal pero ahora en Java. A continuación les dejaré la letra propuesta en aquel momento, pero antes debemos ver cómo generar números aleatorios en Java. Esto será un simple acercamiento al tema ya que Java nos provee varias opciones a la hora de generar un número al azar.

Existe una clase llamada Random la cual está en el paquete java.util. Debemos declarar un objeto de esta clase e inicializarlo para luego, a través de él, generarnos números al azar. Veamos un ejemplo sencillo de un programa que genera números aleatorios entre el 0 y el 5:

Código:

import java.util.Random;

public class Aleatorio {     public static void main(String[] args){         Random generador= new Random(); //Mi objeto de tipo Random.                 int numeroAleatorio; //Mi variable para guardar el número generado.                 numeroAleatorio= generador.nextInt(6); //Obtengo el número generado.                 System.out.println(numeroAleatorio);     }//Fin de main. }//Fin de Aleatorio.

Como ven tenemos una operación de Random llamada nexInt que toma un entero como argumento y nos devuelve otro entero entre 0 y el valor pasado menos 1 (igual que Pascal). En este caso pasé un literal entero como argumento pero bien podía ser una variable entera.

Presten atención a la letra que les dejaré porque hay una pequeña variante.

Page 43: Curso Java - Foro Lospillaos

Ejemplos de ejecución:

Ejemplo 1:

Cita:

Ingresa el número máximo a adivinar: 8

ERROR – Ingresa un número mayor que 10

Ingresa el número máximo a adivinar: 50. Ingresa el número máximo de intentos: 10

Dispones de 10 intentos para adivinar. 1)--> 98 ¡¡¡Muy bien!!! ¡¡¡Has adivinado!!!

Ejemplo 2:

Cita:

Ingresa el número máximo a adivinar: 120 Ingresa el número máximo de intentos: 20

Dispones de 20 intentos para adivinar. 1)--> 99 Lo siento, no has acertado. El número que debes adivinar es menor.

Dispones de 19 intentos para adivinar. 2)--> 80 Lo siento, no has acertado. El número que debes adivinar es mayor.

Dispones de 18 intentos para adivinar. 3)--> 85 ¡¡¡Muy bien!!! ¡¡¡Has adivinado!!!

Ejemplo 3:

Cita:

Ingresa el número máximo a adivinar: 1200 Ingresa el número máximo de intentos: 50

Dispones de 50 intentos para adivinar. 1)--> 60 Lo siento, no has acertado. El número que debes adivinar es menor. . . . Dispones de 1 intentos para adivinar. 50)--> 13 Lo siento, no has acertado. Lamentablemente has perdido. El número era 856

Pequeña mejora del Adivinador:

Mejoraremos un poco el algoritmo del programa Adivinador de la siguiente manera:

• El usuario puede ingresar como rango máximo cualquier número mayor que 10, de lo contrario el programa le avisará como en el programa anterior.

Page 44: Curso Java - Foro Lospillaos

• El número máximo de intentos no puede ser menor que el rango máximo divido 10. Por ejemplo, si el rango máximo es 500, el número de intentos no puede ser menor que 50. Si el usuario ingresa un rango menor al mínimo el programa se lo notificará de este modo:

Cita:

Ingresa el rango máximo a adivinar: 520

Ingresa el número máximo de intentos: 25

ERROR – Muy pocos intentos. Los intentos máximos deben ser mayores o iguales a 52.

Ingresa el número máximo de intentos: 52

Es un agregado sencillo que prácticamente no complica mucho la estructura que ya tengan de su programa.

TIPOS DE DATOS DEFINIDOS POR EL PROGRAMADOR

Este es uno de los aspectos de Java en donde encontraremos más diferencia respecto a Pascal y Modula. En aquellos dos lenguajes teníamos los siguientes tipos a definir como programadores:

• Enumerados. • Subrangos. • Arreglos. • Registros. • Conjuntos (Set – no lo utilizamos). • Punteros.

Los enumerados en Java no existían hasta hace muy poco. Su uso igualmente difiere bastante del que les dábamos, pero lo veremos poco a poco. Igualmente, de los tipos listados arriba, en Java solo quedan estos:

• Enumerados. • Arreglos.

¿Cómo? Pues sí, la forma en que funciona Java hace que cosas como registros, conjuntos o subrangos no se hagan necesarias como tipo predefinido por el lenguaje, sino que nosotros mismos con las clases podemos lograr incluso mejores resultados que con los registros (por ejemplo). De esta manera, veremos estos dos tipos a definir para luego pasar a la declaración de funciones y procedimientos y así llegar a la orientación a objetos en Java donde empezaremos a ver realmente el potencial de este lenguaje, ya que hasta ahora solo hemos repasado conceptos ya asimilados traduciéndolos a la sintaxis de Java.

ENUMERADOS: Como dije, los enumerados no existían en Java hasta hace poco. Esto indica que podíamos lograr sin ellos los mismos resultados que lográbamos con ellos en Pascal o Modula. Sin embargo su existencia nos facilita muchas tareas y su uso en Java aún más. En principio veremos un uso idéntico al que ya conocemos y más adelante, con la Programación Orientada a Objetos veremos más.

En Java un enumerado se declara así:

Código:

enum identificador {valor1, valor2, … , valorN}

Noten que no lleva punto y coma al final de la declaración.

Page 45: Curso Java - Foro Lospillaos

El enumerado no puede estar declarado dentro de un procedimiento sino que debe ir fuera, recomendablemente declarado al inicio de la clase. Esto es, además de por muchos otros motivos, porque el enumerado funcionará como si fuera un tipo de datos, por tanto luego para trabajar con él necesitaremos declarar variables de este tipo. Veamos un ejemplo:

Código:

public class EjemploEnumerados {     enum Meses {Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio,    Agosto, Setiembre, Octubre, Noviembre, Diciembre}         public static void main(String[] args){         Meses mes= Meses.Enero;             } }

Este programa no hace nada, solo muestra como he declarado un enumerado llamado Meses con los meses del año y luego, dentro del main, como he declarado una variable del tipo Meses llamada mes a la cual he inicializado con el valor Enero. Es importante que noten la diferencia entre el uso de los enumerados en Pascal y Modula al de Java. En los anteriores lenguajes podíamos dar a una variable de un tipo enumerado un valor de él simplemente escribiéndolo, por ejemplo:

Código:

Type     Meses= (Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Setiembre, Octubre, Noviembre, Diciembre); Var     mes: Meses;

Begin     Mes:= Enero; End;

En Java tenemos que anteponer el tipo de la variable, un punto y luego el valor a asignar tal como ven en el ejemplo anterior:

Código:

mes= Meses.Enero;

Algo nuevo e interesante es que en Pascal o Modula no podíamos imprimir en pantalla una variable de tipo enumerado directamente, sino que teníamos que, por ejemplo, usar un CASE para imprimir su valor, algo más o menos así:

Código:

CASE mes OF     Enero: WriteString(“Enero”)|    Febrero: WriteString(“Febrero”)|    . . .    Diciembre: WriteString(“Diciembre”)| END;

Ahora sí podemos hacerlo, por ejemplo:

Código:

Page 46: Curso Java - Foro Lospillaos

System.out.println(mes);

Con eso saldrá en pantalla el valor de la variable mes tal cual lo declaramos en el enumerado. Hagan ustedes mismos la prueba para comprobarlo. Esto es debido a la forma de funcionar que tiene Java, acerca de la cual iremos aprendiendo poco a poco.

USANDO UNA VARIABLE DE TIPO ENUMERADO EN UN SWITCH: Esto es una simple aclaración ya que no es intuitivo. Si quisiéramos por algún motivo utilizar una variable de tipo enumerado en una instrucción switch, al escribir las etiquetas no debemos anteponer el nombre del tipo enumerado tal como lo hacemos con las asignaciones, sino que ponemos el literal del valor como lo hacíamos en Pascal y Modula. Por ejemplo:

Código:

switch(mes){      case Enero: //Algo para hacer.                break;      case Febrero: //Algo para hacer.                 break;

     .  .  . }

En este ejemplo he puesto break, pero ya saben que no es obligatorio y qué es lo que sucede en caso de no colocarlo.

ARREGLOS: La palabra ARRAY ya deja de existir dentro del lenguaje. La declaración de arreglos en Java es bastante diferente a lo que conocemos de Pascal o Modula teniendo además más de una forma de hacerlo. No hace falta declarar un tipo ARRAY ni mucho menos. Si lo que yo quiero, por ejemplo es un arreglo de enteros simplemente me declaro una variable así:

Código:

int[] miArreglo;

Con eso ya tengo un arreglo de enteros. En este caso todavía no tiene ni celdas, simplemente hemos dicho que la variable miArreglo es un arreglo de enteros. ¿Cómo? Pues poniendo los corchetes luego de int. Si yo quisiera declarar una variable que sea un arreglo de números reales, por ejemplo, double, lo hago así:

Código:

double[] reales;

Si sacáramos los corchetes serían simples variables numéricas. Entonces, la declaración genérica de arreglos en Java es así:

Código:

TipoDeDatos[] identificador;

Ahora bien ¿cómo hacemos para decir cuántas celdas tiene el arreglo? Es fácil, por ejemplo, quiero que el arreglo miArreglo tenga seis celdas:

Código:

miArreglo= new int[6];

Page 47: Curso Java - Foro Lospillaos

De forma general sería:

Código:

identificador= new TipoDeDatos[cantidadDeCeldas];

La declaración e inicialización se puede hacer de forma conjunta como con todo en Java, de este modo, podíamos haber declarado e inicializado el arreglo de enteros miArreglo de esta manera:

Código:

int[] miArreglo= new int[6];

En la cantidad de celdas yo he puesto un literal, en este caso 6, pero podemos poner una variable entera. Esto es algo que habían preguntado para Pascal y Módula, es decir, poder generar un arreglo de un tamaño indeterminado inicialmente ya que estaría dado por una variable. De este modo, veamos un programa muy básico que pida un valor al usuario y genere un arreglo con esa cantidad de celdas:

Código:

import java.util.Scanner;

public class EjemploArreglos {     public static void main(String[] args){         Scanner entrada= new Scanner(System.in);                 int cantCeldas;         int[] misNumeros;                 System.out.print("¿Cuántos números desea guardar?: ");         cantCeldas= entrada.nextInt();                 misNumeros= new int[cantCeldas];     } }

Teniendo un arreglo, se accede a sus celdas de manera idéntica a Pascal y Modula:

Veamos un ejemplo sencillo con un for que inicialice las celdas de un arreglo con un número al azar entre 0 y 9 y luego lo imprimimos en la salida estándar. El largo del arreglo será dado por una constante:

Código:

import java.util.Random;

public class EjemploArreglos {     public static void main(String[] args) {         final int LARGO_ARREGLO= 10;                 Random generadorAleatorio= new Random();         int[] arreglo= new int[LARGO_ARREGLO];                 for(int i=0; i<LARGO_ARREGLO; i++)             arreglo[i]= generadorAleatorio.nextInt(10);                 for(int i=0; i<LARGO_ARREGLO; i++)             System.out.print(arreglo[i]+" ");     }

Page 48: Curso Java - Foro Lospillaos

}

Algo a destacar es que Java siempre numera las celdas de los arreglos a partir del 0.

Un código muy sencillo y corto. Léanlo con tranquilidad.

Inicialización explícita de arreglos:

Java nos provee de una forma de declarar arreglos poniendo explícitamente los valores de sus celdas. Por ejemplo, si quiero un arreglo de tres celdas con los valores 10, 28 y 77 puedo hacer esto:

Código:

int[] miArreglo= {10,28,77};

Allí la variable miArreglo es un simple arreglo de tres celdas. Luego podemos hacer con él lo que queramos.

Arreglos multidimensionales:

Bien, en Java declarar un arreglo, por ejemplo, de dos dimensiones (una tabla) no tiene más ciencia que esto:

int [][] miTabla= new int[10][5];

Ahí tenemos un arreglo de 10 filas por 5 columnas. Como ven, es solo poner tantos [] como dimensiones queramos y ya. Luego, al hacer new debemos poner los valores para cada dimensión del arreglo y listo.

Del mismo modo se accede a un arreglo multidimensional:

Código:

miTabla[1][2]= 25;

Así podemos tener arreglos de N dimensiones.

Declaración multidimensional explícita:

¿Qué pasa si yo quiero tener una tabla pero inicializarla explícitamente como con un arreglo normal? Pues Java nos permite hacerlo tranquilamente. Supongamos que queremos un arreglo de 2x2:

Código:

int[][] miTabla= {{10,5},{40,22}};

No es lo más usual, pero se puede hacer.

Largo de un arreglo:

Los arreglos en Java son objetos propiamente dichos y, aunque aún no los usamos como tales, tienen ciertas características importantes a tener en cuenta, sobre todo si se desea usarlo en funciones y procedimientos.

Lo único que veremos ahora es que existe una constante llamada length que nos da el largo de un arreglo como int. Si por ejemplo yo quiero guardarme en una variable el largo del arreglo puedo hacerlo así:

Page 49: Curso Java - Foro Lospillaos

Código:

int largo= miArreglo.length;

Noten que no estamos usando una operación, por eso no hay paréntesis. Estamos accediendo a una constante. De momento esto no está claro ya que corresponde a la orientación a objetos de Java. Los arreglos son objetos de una clase llamada Array. Si ustedes la buscan con NetBeans, de todas las que aparecen deberán cliquear sobre la que está en el paquete java.lang.reflect. Allí tienen el código fuente del funcionamiento de los arreglos. No entenderán nada por tres principales motivos:

• No hemos visto orientación a objetos en Java aún. • No hemos visto la declaración de funciones y procedimientos. • La clase Array utiliza en algunos bloques código fuente que no está escrito en Java.

NOTA: Para arreglos multidimensionales, length solo nos devolverá el largo de la primera dimensión declarada. Por ejemplo:

Código:

int[][] miTabla= new int[10][50];

Con length tendremos el valor 10.

Si queremos obtener el largo de una segunda dimensión hacemos por ejemplo:

Código:

miTabla[1].length

Hagan pruebas ustedes mismos. Java permite arreglos con columnas de largos diferentes.

SOLUCION1 Del Adivinador

Código:

import java.util.Scanner; import java.util.Random;

public class Adivinador {     public static void main(String[] args){             Scanner Entrada= new Scanner(System.in);     Random  Generador= new Random();         int Nmax, opcion ,Imax,Nadivinar,adivinar,iactuales,irestantes,obtenido;     boolean a=true,ganado=false;         System.out.print("\n1)Jugar Ahora \n2)Salir"             + "\n\nOpcion:");     opcion=Entrada.nextInt();            switch(opcion){                                case 1: do {               if (a==false) System.out.print("\n\nERROR Ingresa un numero mayor que 10");              

Page 50: Curso Java - Foro Lospillaos

               System.out.print("\n\nIngresa el numero maximo a adivinar:");                Nmax=Entrada.nextInt();                             if (Nmax>10) a=true; else a=false;              }while(a==false);            a=true;                        do{                if (a==false){ System.out.print("ERROR - muy pocos intentos."                        + " Los intentos deben ser mayor o igual que " + (Nmax/10) );}                                   System.out.print("\n\nIngresa el numero maximo de intentos:");           Imax=Entrada.nextInt();                     if (Imax>=(Nmax/10)) a=true; else a=false;                                }while(a==false);                                Nadivinar= Generador.nextInt(Nmax);                                                System.out.print("\n\nDispones de "+ Imax + " Intentos \n    !!A Jugar!! ");                iactuales=1;                irestantes=Imax;                                do{                                    System.out.print("\n\nDispones de "+ irestantes + "\n" + iactuales                          + ")--> ");                obtenido= Entrada.nextInt();                                if(obtenido==Nadivinar){ ganado=true; irestantes=0; }else{                                        if (obtenido>Nadivinar) System.out.print("\nEl numero a adivinar es menor"); else{                                            System.out.print("\nEl numero a adivinar es mayor");                    }                                                ganado=false; iactuales=iactuales+1; irestantes=irestantes-1;                                    }                                                                                                } while((irestantes!=0)||(ganado=false) ) ;                                   if (ganado=true)System.out.print("!!HAS GANADO FELICIDADES!!"); else{                   System.out.print("Has perdido , el numero era "+ Nadivinar);               }                                                  break;                            case 2: break;                            default: System.out.print("Has introducido una opcion incorrecta");                                        }     }            }

SOLUCION2 ADIVINADOR

Código:

1. package adivinador;2.3. import java.util.Random;4. import java.util.Scanner;5.6. public class Adivinador {7.8. public static void main(String[] args) {9. Random generador= new Random();//Creo el objeto Random10. Scanner entradaEstandar= new Scanner(System.in); //Creo el objeto de entrada

Page 51: Curso Java - Foro Lospillaos

por teclado11. int maxRango, maxIntentos, num, numeroAleatorio, contador=1;12.13. do{14. System.out.println("Ingresa el rango maximo a ingresar: ");15. maxRango= entradaEstandar.nextInt();16. if(maxRango<10)17. System.out.println("ERROR! Ingresa un numero mayor o igual que 10");18.19. }while (maxRango <10);20.21. numeroAleatorio= generador.nextInt(maxRango);22.23. do{24. System.out.println("Ingresa el numero maximo de intentos: ");25. maxIntentos= entradaEstandar.nextInt();26. if(maxIntentos < maxRango/10){27. System.out.println("ERROR – Muy pocos intentos. Los intentos máximos

deben ser mayores o iguales a " + maxRango/10);28. }29. }while (maxIntentos < maxRango/10);30.31. entradaEstandar.nextLine(); //Salto de linea32.33. do{34. System.out.println("Dispones de "+maxIntentos +" intentos para

adivinar.");35. System.out.println(contador+")--> ");36. num= entradaEstandar.nextInt();37. System.out.println(num);38. if(num != numeroAleatorio){39. System.out.println("Lo siento no has acertado.");40. if(num < numeroAleatorio)41. System.out.println("El número que debes adivinar es mayor.");42.43. else if(num > numeroAleatorio)44. System.out.println("El número que debes adivinar es menor.");45. maxIntentos=maxIntentos -1;46. contador++;47. }48. else if(num==numeroAleatorio)49. System.out.println("Muy bien!! Has adivinado!!");50.51. }while (num != numeroAleatorio && maxIntentos > 0);52.53. if (maxIntentos==0)54. System.out.println("Lamentablemente has perdido. El número era

"+numeroAleatorio);55.56.57. }58. }59.60.

LECCIÓN 67: OPERACIONES EN JAVA - INTRODUCCIÓN A LA POO.La mejor manera, según mi criterio, de introducir las operaciones en Java es creando algún tipo de objeto que las utilice. Esto es porque si lo hago directamente sobre la clase principal, tendríamos que usar el modificador static para crear operaciones utilizables en el método main, pero es difícil entender eso del static si aún no se han creado objetos. Así que vayamos a ello.

Haremos lo siguiente:

Crearemos un nuevo proyecto llamado DatosPersonas. Crearemos una clase principal llamada también DatosPersonas la cual tendrá por supuesto el procedimiento main. Luego crearemos otra clase llamada

Page 52: Curso Java - Foro Lospillaos

Persona que definirá los objetos del tipo Persona. Trabajaremos sobre dicha clase hasta aprender todos los conceptos necesarios para que quede idéntica al módulo Persona de nuestro pequeño sistema en Modula 2 al cual habíamos llamado NominaPersonas.

Bien, comencemos poco a poco:

Creamos el nuevo proyecto tal como hemos hecho hasta ahora. Creamos una clase y la llamamos DatosPersona. Su código fuente será el mínimo indispensable para

que sea reconocida como clase principal, es decir

Código:

1. public class DatosPersonas {

2. public static void main(String[] args){

3.

4. }

5. }

Creamos una clase llamada Persona. Su código fuente será simplemente este:

Código:

6. public class Persona{

7.

8. }

Es decir que solo está declarada como clase pública y nada más. Recuerden que para declarar una clase simplemente va la palabra class, luego el identificador y las llaves de apertura { y cierre } que forman el cuerpo de la clase. En este caso agregamos además el modificador public para que la clase sea accesible desde otros módulos del programa.

En Modula teníamos aquello de archivo de definición y archivo de implementación. Como dije antes, en Java todo está en el mismo archivo, es decir, en la clase. Las clases definen por sí mismas tipos de objetos que podemos crear con ellas. De este modo, al definir una clase Persona, ya estamos definiendo una futura creación de objetos de tipo Persona.

En Modula teníamos que definir en el archivo de definición que íbamos a usar un tipo de objetos de ese módulo. Eso lo hacíamos con los tipos opacos. Ahora olvidamos ese aspecto porque la propia declaración de la clase define que se crearán objetos de ese tipo.

Luego, en Módula debíamos ir al archivo de implementación y dar una representación para el tipo de objetos que íbamos a crear. Esto lo hacíamos con un puntero a un registro que definíamos en el mismo módulo. Por ejemplo, el tipo Persona del sistema NominaPersonas era así:

Código:

1. TYPE

2. Persona= POINTER TO DatosPersona

3.

4. DatosPersona= RECORD

5. Nombre, Apellido: TipoNombre;

6. Edad, Documento: CARDINAL;

7. SueldoPorHora: REAL;

8. HorasTrabajadas: REAL;

Page 53: Curso Java - Foro Lospillaos

9. END;

10.

Antes dije que en Java no podemos manejar punteros y también dije que no tenemos registros. Así que esa definición de arriba solo nos servirá como modelo. Tomemos de ese tipo simplemente los datos Nombre y Apellido, es decir, de momento nuestros objetos Persona tendrán solo un nombre y un apellido. ¿Cómo definimos eso en Java? Pues fácil, declaramos dos variables para esos datos y ya:

Código:

1. public class Persona {

2. public String nombre;

3. public String apellido;

4. }

Como ven solo declare dos variables del tipo String, pero… ¿qué es eso de public en las variables?

Esa palabra la han visto ya al declarar la clase. Se trata de un modificador de acceso; en este caso quiere decir que esas variables son públicas de la clase Persona, es decir, podemos acceder a ellas desde otra clase cualquiera. Es casi como si fueran variables declaradas en el DEF de un módulo de Modula 2. Vamos un ejemplo:

Ya tenemos entonces nuestra clase Persona declarada la cual tiene dos variables públicas para almacenar un nombre y un apellido. Vamos entonces a la clase principal y nos declaramos una variable llamada p del tipo Persona:

Código:

1. public class DatosPersonas {

2. public static void main(String[] args){

3. Persona p;

4.

5. }

6. }

Sabiendo ustedes que p entonces será un objeto de tipo Persona, deberían ya deducir entonces que p en realidad es una referencia a un objeto de tipo Persona. La variable p contendrá la dirección de memoria en donde estará el objeto Persona con su nombre y su apellido.

Ahora p está simplemente declarada por lo cual no sabemos qué valor posee, incluso si quisiéramos usarla ahora NetBeans no daría un error de sintaxis porque la variable no está inicializada.

¿Cómo la inicializo? Pues en Modula teníamos una operación constructora llamada CrearPersona, la cual se encargaba de solicitar memoria y apuntar al puntero a dicho lugar de memoria. Esta operación además se encargaba de asignar los valores de los atributos ya que los recibía como argumentos. Recordémosla:

Código:

1. PROCEDURE CrearPersona(documento: INTEGER; nombre, apellido:

Page 54: Curso Java - Foro Lospillaos

TipoNombre; edad: INTEGER; sueldo, horas: REAL): Persona;

En Java también necesitamos una operación constructora, sin embargo, como no la hemos definido Java nos da una por defecto la cual recibe el mismo nombre de la clase y no requiere argumentos. Las operaciones constructoras en Java siempre se usan mediante el operador new. De este modo, para inicializar la variable p hacemos

Código:

1. p= new Persona();

El operador new, al igual que en Pascal y Modula solicita memoria para almacenar un objeto y la reserva. Mediante la operación constructora se encarga, luego de haber pedido memoria, de inicializar los atributos del objeto retornando finalmente la dirección de memoria hacia él. A nosotros no nos importa la dirección de memoria ni cómo se escribe, nos importa que p es una referencia a un objeto y ya; o sea, seguiremos viendo a p como una flecha hacia una entidad de memoria que contiene muchos datos manipulables.

¿Cómo sabe la operación constructora cómo inicializar los atributos del objeto? Seguramente ahora eso de una operación constructora por defecto suena raro. Pues bien, como no hemos escrito nada sobre esta operación, sino que nos apegamos a la que Java nos da, debemos saber que los atributos se inicializarán entonces con valores predeterminados:

Variables de tipos primitivos se inicializan en 0 o en FALSE si son booleanos. Variables que son referencias a objetos se inicializan en null (lo veremos luego).

En este caso, nuestra clase Persona tiene solo dos atributos: nombre y apellido. Estos atributos son del tipo String, por tanto no son tipos primitivos sino que son referencias a objetos así que se inicializarán en null. Esto significa que son Strings nulos, lo cual no es lo mismo que Strings vacíos representados por el valor “”.

EL VALOR NULL: Así como yo podía definir en Pascal y Modula un puntero que no apuntara a nada asignándole el valor NIL, en Java puedo hacerlo también. Sabiendo que las referencias a objetos son punteros a esos objetos, puedo asignar a un puntero el valor NIL, solo que en Java se llama null. Por tanto yo puedo hacer algo como esto:

Código:

1. p= null;

Como null es un valor aplicable a cualquier variable puntero, es decir, a cualquier referencia a objetos, puedo preguntar sobre su valor comparando:

Código:

1. if (p==null)

2. . . .

Esto es igual que en Pascal y Modula.

Page 55: Curso Java - Foro Lospillaos

ACCEDIENDO A ATRIBUTOS PÚBLICOS: Bien, continuando con el ejemplo, tenemos en nuestra clase principal un objeto p del tipo Persona el cual sabemos fue inicializado con valores por defecto de modo que sus únicos dos atributos son nulos.

Completemos el ejemplo asignando un nombre y un apellido al objeto p accediendo directamente a su representación para luego imprimir eso en la salida estándar. Veamos el código fuente de la clase principal completo:

Código:

1. public class DatosPersonas {

2. public static void main(String[] args){

3. Persona p= new Persona();

4.

5. p.nombre= "Kyshuo";

6. p.apellido= "Ayame";

7.

8. System.out.println("Nombre: " + p.nombre + "\nApellido: "

+ p.apellido);

9. }

10. }

Como pueden ver, para acceder a las variables del objeto simplemente ponemos el nombre de la referencia, un punto y luego el nombre de la variable. Es más, si ustedes escriben el nombre de la referencia al objeto de tipo Persona y un punto verán que NetBeans despliega un listado de lo que tenemos disponible. Allí verán las variables que definimos y luego alguna otra cosa más que de momento no sabemos de dónde sale. Ya investigaremos sobre el tema.

Si al escribir una referencia a un objeto seguida de un punto no ven el listado de opciones o bien, NetBeans lo cerró, simplemente presionen ALT Gr + ESPACIO y lo tendrán a su disposición. Resulta muy útil, sobre todo cuando tengamos muchas clases con muchas variables y demás.

De este modo hemos accedido directamente a las variables (atributos) de la clase Persona. Esto únicamente fue posible porque estas variables fueron declaradas como públicas y por tanto podemos acceder a ellas desde otra clase que no sea la clase Persona.

MODIFICADOR DE ACCESO PRIVATE Y OPERACIONES EN JAVA: Lo que hicimos entonces fue definir una clase Persona que declara únicamente dos atributos: nombre y apellido. Estos atributos fueron declarados como públicos y por tanto desde la clase DatosPersonas pudimos acceder a ellos mediante un objeto de la clase Persona referenciado por una variable p. A estas alturas del partido ustedes deberían estar de acuerdo conmigo en que dejar que los usuarios de una clase accedan directamente a sus atributos (representación) de los datos no es la mejor opción. ¿Qué pasa si a mí se me ocurre otra implementación para la clase Persona donde nombre y apellido ya no sean dos variables distintas del tipo String? Veamos un ejemplo:

Código:

1. public class Persona {

2. public String[] nomApell= new String[2];

3.

4. }

Page 56: Curso Java - Foro Lospillaos

Ahora ya no tenemos dos variables String sino que tenemos un arreglo de Strings de dos celdas. La primera celda contendrá el nombre y la segunda contendrá el apellido. Si un usuario pretende utilizar mi nueva clase Persona tendrá que, además de sustituir su antigua clase Persona, modificar el código fuente de su clase principal porque ya no hay una variable nombre y una variable apellido. Si ustedes cambian el código fuente en sus PCs y compilan verán que NetBeans les marcará muchos errores.

Para solucionarlos pueden, o bien dejar la clase Persona como estaba, o bien modificar la clase principal. En este caso no sería un trabajo arduo, pero en un sistema grande ya pueden imaginar que sí.

Esto muestra en un ejemplo práctico que declarar los atributos de una clase como públicos hace que se pierda individualidad en el código, de modo que un cambio en una clase impacta directamente sobre el código fuente de otras. Esto no es para nada lo que queremos. Por eso ya Modula ocultaba la representación del tipo de objetos que implementábamos y nos valíamos de las operaciones para manipular la información.

Volvamos entonces a tener nuestro atributo nombre y nuestro atributo apellido pero ahora declarados como private y no como public:

Código:

1. public class Persona {

2. private String nombre;

3. private String apellido;

4.

5. }

Podemos declarar ambas variables en una sola línea así ¿verdad?

Código:

1. private String nombre, apellido;

NetBeans nos marcará errores aún porque ahora no podemos acceder a estos atributos desde fuera de la clase Persona porque son privados de ella, es decir, no son visibles para otras clases, ni siquiera la principal. Crearemos entonces una operación ModificarNombrePersona y una ModificarApellidoPersona que permitan justamente dar un nombre y un apellido a un objeto Persona.

Declaración de operaciones:

En Java toda operación se declara de la misma manera sin importar si es función o procedimiento:

Código:

tipoDeRetorno identificador (argumentos)

Para el módulo Persona teníamos una operación ModificarNombrePersona que tenía esta firma:

Código:

1. PROCEDRUE ModificarNombrePersona(nombre: TipoNombre; VAR p:

Persona);

En Java sería así:

Código:

Page 57: Curso Java - Foro Lospillaos

1. void ModificarNombrePersona(String nom);

Esto es una operación llamada ModificarNombrePersona que retorna algo del tipo void y recibe como argumento algo de tipo String en un parámetro llamado nom. En Java el tipo void es un tipo nulo, es decir que, una operación que retorna void justamente no retorna nada y por eso sabemos que es un procedimiento. Noten que para los parámetros va primero el tipo y luego el identificador, tal como es para las variables.

¿Y qué pasó con el parámetro por referencia que en Modula era justamente el objeto Persona cuyo nombre modificaríamos? Pues ya veremos que esto no es necesario en Java, además de que ya no existe el pasaje de parámetros por referencia.

La operación ModificarNombrePersona quedaría entonces así:

Código:

1. void ModificarNombrePersona(String nom){

2. nombre= nom;

3. }

¿Cómo sabe Java a qué objeto Persona modificar el nombre? Pues, ¿qué mejor manera que verlo con un ejemplo? Veamos, desde la clase principal, teniendo dos objetos Persona distintos, cómo asignamos un nombre a cada uno:

Código:

1. public class DatosPersonas {

2. public static void main(String[] args){

3. Persona p1= new Persona();//Creo un objeto Persona y lo

referencio con p1.

4. Persona p2= new Persona();//Creo un objeto Persona y lo

referencio con p2.

5.

6. p1.ModificarNombrePersona("Kyshuo"); //Le asigno nombre a

p1.

7. p2.ModificarNombrePersona("Pepe"); //Le asigno nombre a

p2.

8.

9. }

10. }

Como pueden observar, la operación ModificarNombrePersona, al ser una operación de la clase Persona, se hace a través de un objeto de esa clase. De este modo, al escribir

Código:

1. p1.ModificarNombrePersona(“Kyshuo”);

Page 58: Curso Java - Foro Lospillaos

queda totalmente explícito que lo haremos con el objeto p1. Las operaciones que se hacen a través de un objeto de una clase siempre se realizan con esta sintaxis:

Código:

1. referenciaDelObjeto.operacionARealizar(argumentos);

Al tener que, obligatoriamente, anteponer la referencia a un objeto antes del nombre de la operación (separados por un punto) es como si estuviéramos pasando ese objeto como argumento. Por eso no necesitamos explicitarlo como un argumento en la lista de parámetros de la operación como teníamos que hacer en Modula. Esto es algo propio de Java. Para dejarlo claro, en Módula debíamos pasar por referencia un objeto del tipo en cuestión como sucedía con esta operación

Código:

1. PROCEDRUE ModificarNombrePersona(nombre: TipoNombre; VAR p:

Persona);

en Java esto ya no es así. Quitamos el parámetro “objeto” porque quedará explícito al llamar a la operación. Si en Modula teníamos un objeto de tipo Persona referenciado por p1, debíamos llamar a esa operación así:

Código:

1. ModificarNombrePersona(“Kyshuo”,p1);

En Java quedó así:

Código:

1. p1.ModificarNombrePersona(“Kyshuo”);

Esto traerá algunas cositas interesantes a tener en cuenta de ahora en más.

Referencia this: En Módula, al tener la referencia como nombre de un argumento (en la operación ModificarNombrePersona la habíamos llamado p) nos referíamos a ese parámetro para modificar los valores necesarios. Por ejemplo, en ModificarNombrePersona hacíamos:

Código:

1. p^.nombre= nombre;

En Java, no tenemos un argumento explícito del tipo en cuestión. ¿Cómo nos referimos entonces al objeto que nos han pasado en el llamado a la operación? Veamos esto con un simple problema:

Page 59: Curso Java - Foro Lospillaos

En el ejemplo anterior llamé al argumento que pasaba el nombre de la persona nom, pero mejor sería llamarlo nombre, de este modo la firma de la operación ModificarNombrePersona sería

Código:

1. void ModificarNombrePersona(String nombre)

¿Qué pasa si dejo el código anterior?

Código:

1. void ModificarNombrePersona(String nombre){

2. nombre= nombre;

3. }

Dentro de la operación el parámetro nombre funciona como variable local, eso ustedes ya lo tienen clarísimo. Por tanto opaca a la variable nombre global que tenemos declarada como atributo de los objetos Persona, así que la asignación nombre=nombre es asignar al parámetro nombre su propio valor y por tanto la variable global nombre queda intacta. Incluso si ustedes paran el cursor sobre la palabra nombre que usan dentro de la operación ModificarNombrePersona verán que NetBeans les pinta en todo el código a quién están haciendo referencia.

Este problema no lo teníamos en Modula porque al tener el argumento p de tipo Persona hacíamos:

Código:

1. p^.nombre= nombre;

¿Y si hacemos algo parecido en Java? Pues, como el objeto con el que hacen el llamado a la operación es pasado de forma implícita no tenemos un nombre con qué referenciarlo, pero afortunadamente los creadores de Java tenían esto presente y nos dan una referencia para el objeto en cuestión, la cual se llama this. De este modo el código casi completamente correcto de la operación es:

Código:

1. void ModificarNombrePersona(String nombre){

2. this.nombre= nombre;

3. }

Entonces, Java nos provee SIEMPRE, queramos o no, una referencia al objeto con el que hemos llamado a una operación. Esta referencia se utiliza con la palabra reservada this. De este modo, si el llamado a la operación fue

Código:

1. p1.ModificarNombrePersona(“Kyshuo”);

Page 60: Curso Java - Foro Lospillaos

dentro de la operación, la referencia this tendrá el mismo valor que p1, es decir this y p1 serán alias. Espero que esto se entienda, porque es crucial en Java y, aunque de pronto ahora podemos prescindir del uso de this, luego no habrá manera de avanzar sin esta referencia, por tanto les pediré que pregunten todo lo que les haga falta.

Yo creo que una buena forma de adaptarse a esto es pensar que ya no necesitamos para nada declarar en nuestras operaciones un parámetro que sea del tipo del objeto que estamos tratando porque Java siempre lo recibirá de forma implícita y lo llamará this. Es como si en Modula la operación ModificarNombrePersona tuviera esta firma:

Código:

1. PROCEDURE ModificarNombrePersona(nombre: TipoNombre; VAR this:

Persona);

Java entonces SIEMPRE declara por nosotros un parámetro del tipo objeto en cuestión y lo llama this. Con eso nos ahorramos tener que pasar los objetos como argumentos de las operaciones y además no tenemos que declararlos más en los encabezados de las mismas.

No está de más aclarar que el objeto pasado a la operación se pasa por copia (por valor), por eso digo que this y p1 son alias. De este modo realmente es como si en Modula la firma fuera esta:

Código:

1. PROCEDURE ModificarNombrePersona(nombre: TipoNombre; this:

Persona);

FUNCIONES EN JAVA: Como ya dije, las operaciones en Java se declaran siempre de la misma manera sin importar si son procedimientos o funciones:

Código:

1. tipoDeRetorno Identificador (argumentos);

Ustedes ya tienen bien claro que un procedimiento no retorna nada y en cambio una función sí lo hace. De este modo, para declarar un procedimiento le damos el tipo de retorno void, que justamente es el tipo nulo de Java para retornos. Claramente entonces, si ponemos otro tipo de retorno distinto de void estamos declarando una función. Veamos, ahora que nuestra clase Persona tiene sus atributos como privados, cómo utilizar una función para que nos retorne el nombre. Recordémosla primero en Modula:

Page 61: Curso Java - Foro Lospillaos

Código:

1. PROCEDURE ObtenerNombrePersona(p: Persona): TipoNombre;

2. BEGIN

3. RETURN p^.Nombre;

4. END ObtenerNombrePersona;

En Java será:

Código:

1. String ObtenernombrePersona(){

2. return this.nombre;

3. }

Seguimos un poco con el tema de la referencia this. Verán que en Modula hacía falta pasar el objeto Persona como argumento pero, como ya dije, Java siempre lo pasa de forma implícita y le llama this, por tanto no necesitamos declarar ningún argumento para esta operación.

Noten que es una función que retorna algo del tipo String, por tanto podemos usarla a la izquierda de una asignación, cosa que no podemos con un procedimiento.

En Java, las funciones también tienen una sentencia return que sí o sí es requerida, la cual funciona exactamente igual que en Modula, es decir que, llegada a la sentencia return salimos de la operación sin importar si había código por ejecutarse debajo. Mucho ojo con eso.

Los procedimientos, o funciones nulas como los llaman algunos (para mí esa nomenclatura es errónea), no requieren sentencia return porque justamente no retornan nada. Sin embargo podemos poner si queremos una sentencia return vacía:

Código:

1. return;

Si la usamos, NetBeans la subrayará en amarillo y nos dirá que es innecesaria, sin embargo compilará y funcionará correctamente si la dejamos ahí.

No colocar al menos una sentencia return en una función es un error de sintaxis y NetBeans nos lo indicará enseguida. Cuando una función se vuelve compleja y tiene muchos if y bucles tendemos a tener distintas sentencias return de modo que se realizará la una o la otra. NetBeans chequeará que las condiciones aseguren que siempre habrá alguna sentencia return que se ejecutará, si no es así nos dirá que hay un error de sintaxis. Por ejemplo:

Código:

1. if (X>=0) then

2. return “Mayor que cero”;

3. else

4. X= 0;

En ese caso si X es mayor o igual que 0 retornamos un String (suponiendo que ese código corresponde a una función de tipo String), pero si no es así le asignamos a X el valor 0 y ya. En ese caso NetBeans detecta que hay

Page 62: Curso Java - Foro Lospillaos

posibilidad de llegar a un momento en que no haya un return posible (cuando entramos en el else) y nos marcará un error. De este modo tenemos dos opciones:

Agregamos una sentencia return en el else. Tenemos una variable declarada específicamente para guardar el valor a retornar y declaramos así una

única sentencia return fuera del if.

La segunda opción es la más recomendable, cada uno lo hace como quiera. Veamos un ejemplo con el pequeño código de arriba:

Código:

1. . . .

2. String ret; //La variable para retornar algo.

3.

4. if(X>=0)

5. ret= “Mayor que 0”;

6. else{

7. X=0;

8. ret= “Asignado a 0”;

9. }

10.

11. . . .

12. return ret;

OPERACIONES PÚBLICAS Y PRIVADAS:

Las operaciones que hemos declarado en nuestra clase Persona han sido operaciones accesibles desde otras clases, en este caso, las accedíamos desde la clase principal. Esto implica que son operaciones públicas de la clase Persona. En Módula esto se especificaba declarando las operaciones en el DEF ya que lo que allí aparecía justamente era público y se podía usar en otros Módulos. En Java se hace añadiendo el modificador de acceso public antes de declarar la operación:

Código:

1. public void ModificarNombrePersona(String nombre){

2. nombre= nombre;

3. }

4.

5. public String ObtenernombrePersona(){

6. return this.nombre;

7. }

¿Por qué si nosotros no habíamos puesto el modificador public en estas operaciones podíamos acceder externamente a ellas de todos modos? Pues porque si no especificamos ningún modificador de acceso Java implícitamente añade el modificador public, de este modo da igual ponerlo o no ponerlo, pero es una convención de programadores SIEMPRE añadir el modificador public para las operaciones y atributos públicos.

Podemos declarar operaciones como private, es decir, operaciones que no serán accesibles desde fuera de la clase sino que serán privadas de ella. Esto es como si en Modula declaráramos una operación en el MOD que no estuviera en el DEF. Las operaciones privadas son declaradas cuando necesitamos hacer alguna tarea propia de la clase que no tiene por qué ser usada fuera y en efecto, no queremos que se pueda hacer.

Page 63: Curso Java - Foro Lospillaos

Vamos a hacer entonces el TAD Persona que teníamos en Modula pero ahora en Java. Recordemos primero el archivo DEF de este TAD:

Código:

1. (******************************************************************************2. Un objeto Persona estará representado por los siguientes datos:3.4. DOCUMENTO5. NOMBRE6. APELLIDO7. EDAD8. SUELDO POR HORA9. HORAS TRABAJADAS10. Esta interfáz describe las operaciones que se pueden realizar con un objeto del11. tipo Persona.*)12.13. DEFINITION MODULE Persona;14. CONST15. MAX_LARGO_NOMBRE= 50;16. TYPE17. Persona; (*Es un tipo opaco.*)18. (*Tipo para el nombre y el apellido*)19. TipoNombre= ARRAY[1..MAX_LARGO_NOMBRE] OF CHAR;20. (************************************)21. (* CONSTURCOTRAS *)22. (************************************)23.24. (*Crea un nuevo objeto persona a partir de los datos ingresados como parámetros*)25. PROCEDURE CrearPersona(documento: INTEGER; nombre, apellido: TipoNombre;26. edad: INTEGER; sueldo, horas: REAL): Persona;27.28. (************************************)29. (* SELECTORAS *)30. (************************************)31.32. (*Retorna el documento de una persona pasada como parámetro*)33. PROCEDURE ObtenerDocumentoPersona(p: Persona): CARDINAL;34.35. (*Retorna el nombre de una persona pasada como parámetro*)36. PROCEDURE ObtenerNombrePersona(p: Persona): TipoNombre;37.38. (*Retorna el apellido de una persona pasada como parámetro*)39. PROCEDURE ObtenerApellidoPersona(p: Persona): TipoNombre;40.41. (*Retorna la edad de una persona pasada como parámetro*)42. PROCEDURE ObtenerEdadPersona(p: Persona): CARDINAL;43.44. (*Retorna el sueldo que una persona gana por hora trabajada*)45. PROCEDURE ObtenerSueldoPorHora(p: Persona): REAL;

Page 64: Curso Java - Foro Lospillaos

46.47. (*Retorna la cantidad de horas trabajadas por una persona*)48. PROCEDURE ObtenerHorasTrabajadas(p: Persona): REAL;49.50. (*Retorna el sueldo ganado por una persona según el sueldo que gana por51. hora trabajada y la cantidad de horas trabajadas*)52. PROCEDURE CalcularSueldoGanado(p: Persona): REAL;53.54. (************************************)55. (* MODIFICADORAS *)56. (************************************)57.58. (*Asigna un nuevo documento a la persona pasada como parámetro*)59. PROCEDURE ModificarDocumentoPersona(documento: CARDINAL; VAR p: Persona);60.61. (*Asigna un nuevo nombre a la persona pasada como parámetro*)62. PROCEDURE ModificarNombrePersona(nombre: TipoNombre; VAR p: Persona);63.64. (*Asigna un nuevo apellido a la persona pasada como parámetro*)65. PROCEDURE ModificarApellidoPersona(apellido: TipoNombre; VAR p: Persona);66.67. (*Asigna una nueva edad a la persona pasada como parámetro*)68. PROCEDURE ModificarEdadPersona(edad: CARDINAL; VAR p: Persona);69.70. (*Asigna un nuevo sueldo a ganar por hora trabajada para la persona71. pasada como parámetro*)72. PROCEDURE ModificarSueldoPorHora(sueldo: REAL; VAR p: Persona);73. (*Asigna una cantidad de horas trabajadas para la persona pasada ocmo parámetro*)74. PROCEDURE ModificarHorasTrabajadas(horas: REAL; VAR p: Persona);75.76. (************************************)77. (* INFORMACIÓN *)78. (************************************)79.80. (*Imprime los datos de p en el siguiente formato:81. Documento: ValorDelDocumento82. Nombre: NombrePersona83. Apellido: ApellidoPersona84. Edad: EdadPersona85. Sueldo por hora: ValorDelSueldo86. Horas trabajadas: CantidadDeHorasTrabajadas*)87. PROCEDURE ImprimirPersona(p: Persona);88.89. (************************************)90. (* DESTRUCTORAS *)91. (************************************)92.93. (*Liebera la memoria ocupada por p*)94. PROCEDURE DestruirPersona(VAR p: Persona);

Page 65: Curso Java - Foro Lospillaos

95. END Persona.

Como primera observación interesante hay que destacar que el constructor que teníamos en este TAD no lo hemos construido aún en Java y pues, no he hablado mucho de los constructores de este lenguaje, así que vayamos a ello.

CONSTRUCTORES EN JAVA: Hasta ahora solo sabemos que Java nos provee un constructor por defecto el cual posee el mismo nombre de la clase en cuestión y no recibe argumentos. Nosotros, sin tan siquiera declararlo en la clase podemos invocarlo para solicitar memoria y crear el nuevo objeto. El hecho es que este constructor inicializa todos los atributos con un valor por defecto lo cual ya expliqué. ¿Y si no quiero que los atributos se inicialicen por defecto sino que yo quiero darles un valor o hacer tareas en la construcción del objeto? ¿Y si quiero pasar argumentos al constructor para directamente construir un objeto con datos definidos u obtenidos de alguna parte? El constructor que teníamos en Modula recibía todos los datos necesarios para dar valores a todos los atributos del TAD Persona, a esto se le conoce como constructor completo. Sin embargo podríamos haber definido algún constructor con menos argumentos, por ejemplo, solo con el nombre y el apellido, dejando lo demás a la deriva de una inicialización predefinida.

En este ejemplo concreto no tiene mucho sentido hacer tareas en el constructor por defecto, pero a medida que los sistemas a desarrollar se vuelven complejos la forma de inicializar un objeto al crearlo se complicará. Java nos permite entonces:

Crear nuestro propio constructor por defecto (en realidad es sobreescribir el constructor por defecto de Java, pero lo veremos cuando lleguemos a la Herencia).

Crear tantos constructores como necesitemos.

Para inicializar los atributos de un objeto con un valor por defecto a nuestro gusto tenemos dos opciones:

Asignamos dichos valores ya al definir los atributos. Asignamos dichos valores dentro del constructor.

La primera forma sería como muestro a continuación, suponiendo que el código fuente de la clase Persona es este:

Código:

1. public class Persona {

2. private String nombre= "ninguno";

3. private String apellido= "ninguno";

4.

5. public void ModificarNombrePersona(String nombre){

6. this.nombre= nombre;

7. }

8.

9. public String ObtenernombrePersona(){

10. return this.nombre;

11. }

12. }

Como ven, los atributos están inicializados ya en la declaración. Podemos también declarar eso mismo en una sola línea. Lo he hecho por separado para que todo se visualice lo mejor posible.

Ahora escribamos el constructor por defecto y demos los valores allí:

Código:

1. public class Persona {

2. private String nombre;

Page 66: Curso Java - Foro Lospillaos

3. private String apellido;

4.

5. public Persona(){

6. this.nombre= "ninguno";

7. this.apellido= "ninguno";

8. }

9.

10. public void ModificarNombrePersona(String nombre){

11. this.nombre= nombre;

12. }

13.

14. public String ObtenernombrePersona(){

15. return this.nombre;

16. }

17. }

Agregamos a la clase entonces una nueva operación. Esta operación es extraña por dos cosas:

Tiene el mismo nombre de la clase. No tiene ningún tipo de retorno, ni siquiera void.

Los constructores de Java tienen reglas bien específicas las cuales son justamente las de arriba:

[*]Deben llevar el mismo nombre de la clase a la que pertenecen.

[*]No deben tener ningún tipo de retorno asociado, ni siquiera void.

Un constructor en Java, que no recibe argumento ninguno, es justamente el constructor por defecto. Si nosotros declaramos, como hice ahora, un constructor sin argumentos nos estamos definiendo nuestro propio constructor por defecto. Cuando desde fuera se hace, por ejemplo:

Código:

1. p1= new Persona();

estamos justamente llamando a una operación. La diferencia entre los llamados habituales y uno de construcción de un objeto es que estos últimos se hacen mediante el operador new y a la izquierda de una asignación a una referencia. Así que como ven, luego de new va el constructor que queremos invocar.

El tipo Persona en Modula era, como ya habíamos recordado anteriormente:

Código:

1. TYPE

2. Persona= POINTER TO DatosPersona;

3.

4. DatosPersona= RECORD

5. Nombre, Apellido: TipoNombre;

6. Edad, Documento: CARDINAL;

7. SueldoPorHora: REAL;

8. HorasTrabajadas: REAL;

9. END;

Declaremos entonces el resto de los atributos en nuestro TAD Persona de Java, tras lo cual completaremos el código del constructor por defecto para inicializar todos los valores de manera correcta y declararemos además un constructor completo. Hasta ahora la clase Persona es esta:

Page 67: Curso Java - Foro Lospillaos

Código:

1. public class Persona {

2. private String nombre, apellido;

3. private int edad, documento;

4. double sueldoPorHora, horasTrabajadas;

5.

6. public Persona(){

7. this.nombre= "ninguno";

8. this.apellido= "ninguno";

9. }

10.

11. public Persona(String nombre, String apellido, int edad, int

documento,

12. double sueldoPorHora, double horasTrabajadas){

13. this.nombre= nombre;

14. this.apellido= apellido;

15. this.edad= edad;

16. this.documento= documento;

17. this.sueldoPorHora= sueldoPorHora;

18. this.horasTrabajadas= horasTrabajadas;

19. }

20.

21. public void ModificarNombrePersona(String nombre){

22. this.nombre= nombre;

23. }

24.

25. public String ObtenernombrePersona(){

26. return this.nombre;

27. }

28. }

Bien, tenemos entonces dos constructores, es decir, dos operaciones constructoras. Algo que tal vez a ustedes les llame mucho la atención es que tenemos dos operaciones con el mismo nombre. Esto es algo nuevo y se conoce como Polimorfismo, es decir, una misma operación puede tener muchas formas. En este caso tenemos el constructor Persona con dos formas diferentes. ¿Cómo sabrá Java a cual constructor estamos llamando? Pues por la cantidad y el tipo de argumentos. Veamos un ejemplo:

Código:

1. p1= new Persona();

2. p2= new Persona(“Kyshuo”,”Ayame”,23,12345678,80,30);

¿Está claro que para p1 hemos invocado al constructor por defecto y para p2 al constructor completo? Java se da cuenta de cual constructor debe llamar justamente porque uno no recibe argumentos y el otro sí. Asimismo podemos tener muchos constructores distintos siempre que el tipo y la cantidad de argumentos no coincidan a la vez en más de una operación. Por ejemplo:

Código:

1. public Persona(String nombre, int documento);

Page 68: Curso Java - Foro Lospillaos

2.

3. public Persona(String apellido, int edad);

Claramente allí tenemos dos declaraciones distintas, sin embargo ambas tienen dos argumentos cuyos tipos coinciden. Al momento de la invocación Java no puede saber a qué constructor de ambos estamos queriendo llamar y pues por este motivo no nos dejará hacer estas declaraciones. Imaginen esto:

Código:

1. p3= new Persona(“Ermenegildo”, 52);

La referencia p3 pretende ser inicializada mediante el constructor que recibe el nombre y la edad, sin embargo para Java es un constructor que recibe un String y luego un int y no puede diferenciar a cuál queremos invocar.

Si aún así quisiéramos tener esos dos constructores tendríamos que variar en algo, por ejemplo el orden de los argumentos:

Código:

1. public Persona(int documento, String nombre);

2.

3. public Persona(String apellido, int edad);

Ahora sí Java puede diferenciar una operación de otra porque la primera recibe un int y luego un String y la segunda recibe un String y luego un int.

Esto es aplicable a todas las operaciones, pero lo iremos viendo luego.

NOTA: Espero que hayan podido observar que para los argumentos de las operaciones siempre debemos declarar primero el tipo y luego el identificador, separando todos los argumentos con una coma. No es como sucedía en Pascal y Modula donde podíamos declarar varios argumentos de un mismo tipo a la vez separando por coma y luego usando el punto y coma para declarar argumentos de un nuevo tipo. Ahora en Java ponemos el tipo sí o sí por cada argumento.

¿Qué pasa si yo quiero que siempre se use SOLAMENTE el constructor completo para inicializar los objetos Persona?

Muchas veces necesitamos asegurarnos de que no se usará el constructor por defecto para crear algún objeto de una clase que estamos desarrollando ya que necesitamos más información explícitamente para lograr un buen funcionamiento. Una forma bien fácil de lograr esto es declarar el constructor por defecto como privado, así:

Código:

1. private Persona(){}

Como ven, he abierto y cerrado las llaves {}, es decir, ni siquiera puse código fuente en el cuerpo del constructor porque no lo usaremos. Podría haberlo hecho si pretendiera usarlo internamente, pero para la clase Persona podríamos querer que siempre se inicialice con el constructor completo a fin de garantizarnos que siempre se creará un nuevo objeto con datos sustanciales. De este modo ya tenemos esa garantía, los clientes de mi clase no tendrán más que usar el constructor completo.

Ejercicio: Dado el TAD Persona que usamos en Modula 2 tal como lo he mostrado anteriormente, reescríbanlo en Java exceptuando la operación DestruirPersona. Esto último viene a que la destrucción de objetos en Java es muy distinta a la que conocen (lo veremos luego).

Page 69: Curso Java - Foro Lospillaos

Modifiquen el método main de modo que pida al usuario un entero para la cantidad de personas a almacenar y cree con ese valor un arreglo de personas llamado nominaPersonas. Luego deberá pedir para cada persona los datos ingresados por el usuario e ir guardando dichas personas en el arreglo. Al final debe imprimir los datos de todas las personas cargadas en el formato que mostraré. Veamos un ejemplo de ejecución donde pinto en azul la entrada ingresada por el usuario:

Cita:

Ingrese la cantidad de personas a almacenar: 3

Nombre: Mengano Apellido: Menganoso Edad: 20 Documento: 123456 Sueldo: 15.5 Horas: 30

Nombre: Fulano Apellido: Fulanoso Edad: 20 Documento: 456789 Sueldo: 15.5 Horas: 30

Nombre: Perengano Apellido: Perenganoso Edad: 18 Documento: 258963 Sueldo: 12.3 Horas: 10

Los datos ingresados han sido:

Mengano Menganoso, 20 años, documento 123456, sueldo $15.5 la hora, horas trabajadas 30. Fulano Fulanoso, 20 años, documento 456789, sueldo $15.5 la hora, horas trabajadas 30. Perengano Perenganoso, 18 años, documento 258963, sueldo $12.3, horas trabajadas 10.

Este ejercicio será una gran práctica para ustedes. Por favor, háganlo.

LECCIÓN 69: DESTRUCCIÓN DE OBJETOS EN JAVA.En nuestra clase Persona, la cual tomamos del módulo Persona escrito en Modula, nos omitimos la operación DestruirPersona. Esto se debe a que no tenemos una operación DISPOSE que nos permita liberar la memoria ocupada por un objeto justamente para evitarnos el tener que preocuparnos por la memoria usada por nuestros programas. De este modo, al menos en objetos simples como los que describe la clase Persona no tiene sentido una operación que los destruya, es más, no tenemos cómo implementarla.

¿Cómo liberamos entonces la memoria usada por nuestros objetos? Pues en Pascal y Modula teníamos que tener especial cuidado de no dejar colgados a nuestros objetos porque luego quedaban inaccesibles y ocupando lugar de memoria. Esto claramente era una mala práctica de programación. Por ejemplo, si en Modula hacíamos:

Código:

1. p= CrearPersona(“Kyshuo”,”Ayame”);

2. p= CrearPersona(“Mengano”,”Menganoso”);

Claro debería ser para ustedes el error allí. Primero hemos creado un objeto Persona referenciado por p y

Page 70: Curso Java - Foro Lospillaos

luego hemos creado otro objeto Persona referenciado también por p. Esto hace que p deje de apuntar al primer objeto creado y quede apuntando al segundo. De este modo, el objeto con nombre Kyshuo Ayame queda perdido en memoria, inaccesible y ocupando espacio. Lo correcto habría sido destruir el objeto Persona Kyshuo Ayame antes de crear el nuevo, o bien, referenciar dicho objeto con otra variable.

Asimismo, suponiendo que p y q son punteros a enteros, cosas como estas están mal:

En esos los dos primeros casos estamos dejando memoria colgada, y en el tercer caso teníamos que p y q eran alias y luego, al disponer uno de ellos el otro queda indefinido también lo cual era muy peligroso si el programador no se daba cuenta porque al intentar acceder a un puntero indefinido tendría un error en tiempo de ejecución.

En Java para liberar memoria justamente tenemos que dejarla colgada. ¿¿¿!!!QUÉ¡¡¡??? Sí, tenemos que dejar memoria colgada porque Java será quién se encargue de liberarla luego, nosotros no tenemos control sobre eso. De este modo, si yo hago en Java algo como esto:

Código:

1. p= new Persona(“Kyshuo”,”Ayame”);

2. p= null;

estoy dejando el objeto creado en la primera línea colgado en memoria e inaccesible. Justamente eso es lo que Java necesita saber para liberar esa memoria luego. O sea que, para liberar memoria tengo que, a propósito, dejarla colgada. Así, todo lo que estaba mal en Modula y Pascal ahora en Java no nos da problemas.

Por ejemplo, el tercer caso visto recién en Modula en Java sería:

Código:

1. p= new Persona(“Kyshuo”,”Ayame”);

2. q= p;

3. p= null;

Allí hemos dejado la referencia p en null pero no hemos afectado a q por tanto el objeto creado no está inaccesible y por ende no está colgado en memoria.

Entonces ¿cómo funciona realmente esto de la gestión de memoria en Java?

RECOLECCIÓN DE BASURA Como estamos viendo, para liberar memoria tenemos que dejarla colgada, no tenemos otro modo. Esto es porque en Java existe un proceso llamado Garbage Collector (recolector de basura) que cada tanto tiempo se ejecuta y busca en memoria los objetos que están inaccesibles desde el programa principal liberando la memoria ocupada por ellos, es decir, este proceso se encarga justamente de buscar y liberar todo lo que hemos dejado colgado y que por tanto se considera basura. Entonces, el recolector de basura elimina de memoria todo aquello que no está referenciado por nadie o bien, que no es accesible desde el programa principal (veremos esto en detalle).

¿Cuándo pasa el recolector de basura? Este proceso es ejecutado por la máquina virtual de Java y nosotros como programadores no tenemos ningún control sobre él, por tanto se ejecuta esporádicamente o cuando el sistema necesita memoria para otra cosa. Nunca se sabe entonces cuando será ejecutado este proceso. Otro punto importante es que la ejecución del recolector de basura no implica necesariamente que se eliminen todos los objetos que son considerados basura. Por tanto, si hemos dejado cinco objetos colgados, cuando el recolector pase no tiene por qué eliminar los cinco objetos. Nosotros tampoco tenemos un control sobre eso.

Page 71: Curso Java - Foro Lospillaos

Existe una instrucción que podemos utilizar para indicar a la máquina virtual de Java que queremos que el recolector de basura pase para limpiar la memoria la cual es:

Código:

1. System.gc();

Sin embargo enfatizaré específicamente la parte de que con esto indicamos a la máquina virtual que QUEREMOS que el recolector pase, pero no implica que la máquina virtual lo ejecute y por tanto esa decisión dependerá de ella. De este modo, por mucho énfasis que pongamos en querer liberar memoria nunca sabremos efectivamente cuando será ejecutado el recolector de basura.

Este proceso es muy inteligente, en el siguiente sentido:

Si tenemos por ejemplo una lista encadenada y perdemos la referencia al primer nodo estamos dejando entonces todo el contenido de la lista colgado en memoria. En un caso así, a pesar de que cada nodo referencia al siguiente y por ende existen objetos que son referenciados por alguien, el recolector de basura puede determinar que en realidad no podemos llegar a ninguno de ellos desde el programa principal.

Lo mismo sucede con una lista circular, un árbol binario, o cualquier estructura de memoria dinámica.

Esto implica entonces que el recolector de basura puede determinar cuando toda una enorme estructura llena de punteros que referencian a objetos de todos lados son basura o no. Si a es una referencia a un árbol binario de búsqueda que contiene miles de nodos y yo hago a=null, el recolector de basura podrá determinar que no es posible llegar a ningún nodo del árbol desde el programa principal y por tanto lo eliminará todo, ya no tenemos que programarlo nosotros.

La contraparte de esto es que la recolección de basura es entonces un proceso muy pesado y que consume recursos, por este motivo es la máquina virtual la que decide cuando es necesario ejecutarlo, lo cual dependerá de la necesidad del sistema operativo por usar la memoria ocupada, la carga del procesador en el momento actual (si el procesador está muy ocupado no conviene ejecutar el recolector), la necesidad de nuestro programa por obtener nueva memoria, etc. Toda esta complicación queda por parte de los programadores de Java y por tanto nosotros solo la utilizamos.

Ejemplo:

Crearemos entonces cuatro objetos de tipo Persona y luego los eliminaremos, es decir, los desreferenciaremos con el fin de que queden como basura, inaccesibles por nosotros y por tanto nos desentenderemos de ellos porque sabemos que Java los eliminará en algún momento:

Código:

1. public class DatosPersonas {

2. public static void main(String[] args){

3. Persona p1= new

Persona("Kyshuo","Ayame",23,12345678,80,30);

4. Persona p2= new

Persona("Kyshuo","Ayame",23,12345678,80,30);

5. Persona p3= new

Persona("Kyshuo","Ayame",23,12345678,80,30);

6. Persona p4= new

Persona("Kyshuo","Ayame",23,12345678,80,30);

7.

Page 72: Curso Java - Foro Lospillaos

8. System.out.println(Persona.obtenerCantidadPersonas());

9.

10. p1= null;

11. p2= null;

12. p3= null;

13. p4= null;

14. }

15. }

Hasta ahí todo bien, sin embargo si ustedes vuelven a mostrar en pantalla el valor de la variable cantidadPersonas verán que vuelve a salir el número 4. Entonces en realidad esta variable lleva un conteo de los objetos instanciados desde el inicio del programa sin tomar en cuenta los eliminados. De este modo si a lo largo del tiempo de ejecución de mi programa creo en total 1500 objetos, sea que hayan convivido en memoria todos a la vez o no, la variable marcará el valor 1500; más claramente, suma 1 cada vez que creamos un objetos, jamás disminuye.

¿Cómo hacemos para restar 1 a la variable cuando se destruya un objeto? Deberíamos saber cuando el recolector de basura elimina efectivamente a un objeto en memoria que es considerado basura. ¿Cómo logramos esto? Pues Java nos provee de una operación ya definida que se ejecuta cuando un objeto va a ser eliminado, es decir, cuando el recolector de basura va a reclamar la memoria ocupada por un objeto que es basura este tiene la posibilidad de ejecutar una última operación antes de ser borrado. Esta operación se conoce con el nombre finalize.

La razón de la existencia de esta operación es darle al programador la posibilidad de liberar algún posible recurso que el objeto pueda estar usando antes de ser eliminado con el fin de tener una buena gestión sobre ese recurso; un ejemplo podría ser la conexión con una base de datos que debería ser cerrada antes de eliminar al objeto que la representa. En este caso puntual nosotros usaremos la operación finalize para restar 1 a la variable cantidadPersonas a fin de que represente realmente la cantidad de objetos de la clase Persona que existen en memoria en un momento dado.

La declaración de la operación finalize es:

Código:

1. public void finalize()

Entonces vallamos a nuestra clase Persona y declaremos esta operación dándole además un método como el que muestro ahora:

Código:

1. public void finalize(){

2. Persona.cantidadPersonas--;

3. }

Verán que NetBeans les subrayará en amarillo a esta operación. En unos momentos veremos por qué. Vallamos ahora a la clase principal de DatosPersonas y agreguemos estas dos líneas a lo que ya teníamos:

Código:

Page 73: Curso Java - Foro Lospillaos

1. System .gc();

2.

3. System .out.println(“Objetos en memoria

”+Persona.obtenerCantidadPersonas());

¿Qué hicimos? Pues agregamos un llamado al recolector de basura para intentar que el sistema lo ejecute. Luego mostramos en pantalla cuantos objetos quedan efectivamente en memoria luego del llamado. Ejecuten el programa varias veces y verán que el resultado puede variar. Eso dependerá de si realmente el recolector de basura fue ejecutado y además, en caso afirmativo, dependerá de si fueron eliminados todos los objetos basura. Por ejemplo, a mí me salió que luego del llamado aún permanecían en memoria los cuatro objetos creados, pero tras varias ejecuciones resultó que siempre se eliminaban todos los objetos. Hagan ustedes sus propias pruebas.

Tengan en cuenta que la variable cantidadPersonas indicará entonces la cantidad de objetos de tipo Persona que existan en memoria en un momento dado, sea que nosotros tengamos referencias a ellos o no. No es lo mismo que llevar un registro de la cantidad de objetos Persona que nosotros tenemos referenciados.

NOTAS:

A estas alturas, y más aún si alguno de ustedes ha intentado hacer sus propios programas en Java, habrán visto alguna sugerencia de NetBeans aunque puede que no se hayan dado cuenta de ello. En general, NetBeans subraya en amarillo las líneas de código en las que tiene algo que comentarnos agregando además una lamparita en el número que indica la línea en cuestión, tal como en la imagen que sigue

Allí ven que tenemos subrayada la palabra finalize y además vemos la lamparita que está en lugar del número 130. Si hacemos clic en la lamparita veremos que NetBeans nos da opciones acerca de la sugerencia. En este caso particular tendremos tres:

Añadir anotación @Override. Añadir super.finalize(). Configurar “finalize declarado” Hint.

Si hacemos clic en alguna veremos que NetBeans añadirá algún código o nos abrirá algún cuadro de diálogo.

Mas allá de eso, las sugerencias son sugerencias y si no las aceptamos todo funcionará.

Page 74: Curso Java - Foro Lospillaos

Anotación @Override: Las anotaciones, dicho muy superficialmente, son palabras que indican al compilador algún dato importante. Estas palabras siempre están precedidas por el símbolo @. En este caso particular, si ustedes presionan la sugerencia de la anotación verán que NetBeans agregará @Override antes de la declaración del procedimiento finalize. Además marcará con un símbolo verde la línea en que hemos escrito la anotación:

Esta anotación indica al compilador que estamos redefiniendo una operación heredada de otra clase, en este caso, finlize lo estamos heredando de una clase que se llama Object, sin embargo todo eso lo veremos más adelante.

Añadir super.finlize(): Esta sugerencia también tiene un vínculo estricto con lo que tiene que ver con herencia y por tanto de momento la omitiremos ya que además introduce manejo de excepciones, cosa que aún ni he mencionado.

La tercera sugerencia no nos interesa. Si vamos al menú Ver --> Toolbars --> Memoria nos aparecerá esto en la barra de herramientas de

NetBeans:

Es un indicador de la memoria RAM ocupada por NetBeans y lo que nosotros hayamos creado. Si hacemos clic en este indicador NetBeans hará un llamado al recolector de basura y tal vez libere algo de memoria, lo cual se verá reflejado en el indicador.

A pesar de que nuestro procedimiento finalize está declarado como público no es recomendable que sea invocado a propósito por un cliente de nuestra clase ya que haría decrementar la variable cantdiadPersonas aún cuando el objeto no haya sido eliminado por el garbage collector. Incluso si nosotros lo hacemos NetBeans nos avisará con una sugerencia de que estamos invocando a finalize explícitamente y nos invitará a configurar dicho llamado. No nos interesa eso porque en Java todo el mundo sabe que no se debe invocar explícitamente al método de finalize porque esto corresponde al recolector de basura.

Page 75: Curso Java - Foro Lospillaos

http://www.foro.lospillaos.es/curso-gratuito-de-programacion-aprende-desde-0-vt7888.html