Lenguaje de programación Java De Wikipedia, la enciclopedia libre Saltar a navegación navegación,, búsqueda
Java Paradigma:: Paradigma
Orientado a objetos
Apareció en:
1991
Diseñado por:
Sun Microsystems
Tipo de dato: dato:
Fuerte, Estático
Implementaciones: Numerosas Influido por:
Objective-C,, C++ Objective-C C++,, Smalltalk , Eiffel
Ha influido:
C#,, J# C# J#,, JavaScript
Sistema operativo: operativo:
Multiplataforma
Licencia de software: software: GNU GPL / Java Community Process
por Sun Java es un lenguaje de programación orientado a objetos desarrollado por Sun Microsystems a principios de los años 90. 90. El lenguaje en sí mismo toma mucha de su sintaxis de C y C++ C++,, pero tiene un modelo de objetos más simple y elimina herramientas de bajo nivel, que suelen inducir a muchos errores, como la manipulación directa de punteros de punteros o memoria. Las aplicaciones Java están típicamente compiladas en un bytecode, aunque la compilación en código máquina nativo también es posible. En el tiempo de ejecución, ejecución, el bytecode es normalmente interpretado o compilado a código nativo para la ejecución, aunque la ejecución directa por hardware por hardware del bytecode por un procesador un procesador Java también es posible. La implementación original y de referencia del compilador , la máquina virtual y las librerías de clases de Java fueron desarrollados por Sun Microsystems en 1995 1995.. Desde entonces, Sun ha controlado las especificaciones, el desarrollo y evolución del lenguaje a través del Java Community Process, Process, si bien otros han desarrollado también implementaciones alternativas de estas tecnologías de Sun, algunas incluso bajo licencias de software libre. libre. Entre noviembre de 2006 y mayo de 2007 2007,, Sun Microsystems liberó la mayor parte de sus tecnologías Java bajo la licencia GNU GPL, GPL, de acuerdo con las especificaciones del Java Community Process, de tal forma que prácticamente todo el Java de Sun es ahora
software libre (aunque la biblioteca la biblioteca de clases de Sun que se requiere para ejecutar los programas Java todavía no es software libre). libre).
Contenido [ocultar ] 1 Historia • 2 Filosofía • o 2.1 Orientado a Objetos o 2.2 Independencia de la plataforma o 2.3 El recolector de basura 3 Sintaxis • o 3.1 Hola Mundo 3.1.1 Aplicaciones autónomas 3.1.2 Applets 3.1.3 Servlets 3.1.4 Aplicaciones con ventanas 4 Entornos de funcionamiento • o 4.1 En dispositivos móviles y sistemas empotrados o 4.2 En el navegador web o 4.3 En sistemas de servidor o 4.4 En aplicaciones de escritorio o 4.5 Plataformas soportadas 5 Industria relacionada • 6 Críticas • o 6.1 General o 6.2 El lenguaje o 6.3 Apariencia o 6.4 Rendimiento 7 Recursos • o 7.1 JRE o 7.2 Componentes o 7.3 APIs o 7.4 Extensiones y arquitecturas relacionadas 8 Java en código abierto • o 8.1 ¿Hasta donde Java es Software libre? o 8.2 Compromiso de Sun Microsystems con el código abierto o 8.3 Alternativas libres o 8.4 Críticas referentes a Java y el software libre o 8.5 Software libre basado en Java 9 Véase también • 10 Referencias • 11 Ejemplos De Programación Dinámica • 12 Notas • 13 Enlaces externos • o 13.1 Sun o 13.2 Tutoriales
o
13.3 Críticas
editar]] Historia [editar
La tecnología Java se creó como una herramienta de programación para ser usada en un proyecto de set-top-box en una pequeña operación denominada denominada the Green Project en Sun Microsystems en el año 1991 1991.. El equipo (Green Team), compuesto por trece personas y dirigido por James por James Gosling, Gosling, trabajó durante 18 meses en Sand Hill Road en Menlo Park en su desarrollo. El lenguaje se denominó inicialmente Oak (por un roble que había fuera de la oficina de Gosling), luego pasó a denominarse Green tras descubrir que Oak era ya una marca comercial registrada para adaptadores de tarjetas gráficas y finalmente se renombró a Java. El término Java fue acuñado en una cafetería frecuentada por algunos de los miembros del equipo. Pero no está claro si es un acrónimo o no, aunque algunas fuentes señalan que podría tratarse de las iniciales de sus creadores: J ames ames Gosling, Arthur V an an Hoff, y ust A ague Andy Bechtolsheim. Otros abogan por el siguiente acrónimo, J ust Another V ague Acronym ("sólo otro acrónimo ambiguo más"). La hipótesis que más fuerza tiene es la que Java debe su nombre a un tipo de café disponible en la cafetería cercana, de ahí que el icono de java sea una taza de cafe caliente. Un pequeño signo que da fuerza a esta teoría es que los 4 primeros bytes (el número mágico ) de los archivos .class que genera el compilador, son en hexadecimal, 0xCAFEBABE. Otros simplemente dicen que el nombre fue sacado al parecer de una lista aleatoria de palabras. Los objetivos de Gosling eran implementar una máquina virtual y un lenguaje con una estructura y sintaxis similar a C++ C++.. Entre junio y julio de 1994, tras una sesión maratoniana de tres días entre John Gaga, James Gosling, Joy Naughton, Wayne Rosing y Eric Schmidt, el equipo reorientó la plataforma hacia la Web. Sintieron que la llegada del navegador web Mosaic Mosaic,, propiciaría que Internet se convirtiese en un medio interactivo, como el que pensaban era la televisión por cable. Naughton creó entonces un prototipo de navegador, WebRunner, que más tarde sería conocido como HotJava HotJava.. En 1994, se les hizo una demostración de HotJava y la plataforma Java a los ejecutivos de Sun. Java 1.0a pudo descargarse por primera vez en 1994, pero hubo que esperar al 23 de mayo de 1995, durante las conferencias de SunWorld, a que vieran la luz pública Java y HotJava, el navegador Web. El acontecimiento fue anunciado por John Gage, el Director Científico de Sun Microsystems. El acto estuvo acompañado por una pequeña sorpresa adicional, el anuncio por parte de Marc Andreessen, Vicepresidente Ejecutivo de Netscape, que Java sería soportado en sus navegadores. El 9 de enero del año siguiente, 1996, Sun fundó el grupo empresarial JavaSoft para que se encargase del desarrollo tecnológico. [2] Dos semanas más tarde la primera versión de Java fue publicada. La promesa inicial de Gosling era Write Once, Run Anywhere (Escríbelo una vez, ejecútalo en cualquier lugar), proporcionando un lenguaje independiente de la plataforma y un entorno entorn o de ejecución (la JVM) ligero liger o y gratuito para las plataformas p lataformas más populares de forma que los binarios (bytecode) de las aplicaciones Java pudiesen ejecutarse en cualquier plataforma.
El entorno de ejecución era relativamente seguro y los principales navegadores web pronto incorporaron incorporaro n la posibilidad de d e ejecutar applets ejecutar applets Java incrustadas en las páginas web. Java ha experimentado numerosos cambios desde la versión primigenia, JDK JDK 1.0, 1.0, así como un enorme incremento en el número de clases y paquetes que componen la librería estándar. Desde J2SE 1.4, la evolución del lenguaje ha sido regulada por el JCP (Java (Java Community Process), Process), que usa Java Specification Requests (JSRs) para proponer y especificar cambios en la plataforma Java. El lenguaje en sí mismo está especificado en la Java Language Specification (JLS), o Especificación del Lenguaje Java. Los cambios en los JLS son gestionados en JSR 901. 901. •
1996)) — Primer lanzamiento. JDK 1.0 (23 de enero de 1996
comunicado de prensa •
•
•
1997)) — Principales adiciones incluidas: JDK 1.1 (19 de febrero de 1997 comunicado de prensa o una reestructuración intensiva del modelo de eventos AWT (Abstract Windowing Toolkit) o clases internas (inner classes) o JavaBeans o JDBC (Java Database Connectivity), para la integración de bases de datos o RMI (Remote Method Invocation) 1998)) — Nombre clave Playground . Esta y las J2SE 1.2 (8 de diciembre de 1998 siguientes versiones fueron recogidas bajo la denominación Java 2 y el nombre "J2SE" (Java 2 Platform, Standard Edition), reemplazó a JDK para distinguir la plataforma base de J2EE (Java 2 Platform, Platf orm, Enterprise Edition) y J2ME (Java (Jav a 2 Platform, Micro Edition). Otras mejoras añadidas incluían: comunicado de prensa o la palabra reservada (keyword) strictfp o reflexión en la programación Swing)) fue integrada en las clases básicas o la API gráfica ( Swing compilador JIT JIT o la máquina virtual (JVM) de Sun fue equipada con un compilador (Just in Time) por primera vez o Java Plug-in o Java IDL, IDL, una implementación de IDL (Interfaz para Descripción de Lenguaje) para la interoperabilidad con CORBA (Collections)) o Colecciones (Collections 2000)) — Nombre clave Kestrel . J2SE 1.3 (8 de mayo de 2000
Los cambios más notables fueron:comunicado fueron:comunicado de prensa lista completa de cambios •
o o o o o •
•
la inclusión de la máquina virtual de HotSpot JVM (la JVM de HotSpot fue lanzada inicialmente en abril de 1999, para la JVM de J2SE 1.2) RMI fue cambiado para que se basara en CORBA JavaSound se incluyó el Java Naming and Directory Interface (JNDI) en el paquete de librerías principales (anteriormente disponible como una extensión) Java Platform Debugger Architecture (JPDA)
2002)) — Nombre Clave Merlin. Este fue el primer J2SE 1.4 (6 de febrero de 2002 lanzamiento de la plataforma Java desarrollado bajo el Proceso de la Comunidad Java como JSR 59. 59. Los cambios más notables fueron: comunicado de prensalista prensalista completa de cambios 41.) o Palabra reservada assert (Especificado en JSR 41.) o Expresiones regulares modeladas al estilo de las expresiones regulares Perl o Encadenación de excepciones Permite a una excepción encapsular la excepción de bajo nivel original. New Input/Output) Input/Output) (Especificado en JSR 51.) 51.) o non-blocking NIO ( New 47.) o Logging API (Specified in JSR 47.) o API I/O para la lectura y escritura de imágenes en formatos como JPEG o PNG Parser XML integrado y procesador XSLT procesador XSLT (JAXP JAXP)) (Especificado en JSR o Parser XML 5 y JSR 63.) 63.) o Seguridad integrada y extensiones criptográficas (JCE, JSSE JSSE,, JAAS JAAS)) o Java Web Start incluido (El primer lanzamiento ocurrió en Marzo de 2001 para J2SE 1.3) (Especificado en JSR 56.) 56.) 2004)) — Nombre clave: Tiger . (Originalmente J2SE 5.0 (30 de septiembre de 2004 numerado 1.5, esta notación aún es usada internamente.[3] internamente.[3])) Desarrollado bajo JSR 176, 176, Tiger añadió un número significativo de nuevas características comunicado de prensa o Plantillas (genéricos) — provee conversion de tipos (type safety) en tiempo de compilación para colecciones y elimina la necesidad de la mayoría de conversion de tipos (type casting). casting). (Especificado por JSR por JSR 14.) 14 .) anotaciones,, permite a estructuras del o Metadatos — también llamados anotaciones lenguaje como las clases o los métodos, ser etiquetados con datos adicionales, que puedan ser procesados posteriormente por utilidades de proceso de metadatos. (Especificado ( Especificado por JSR por JSR 175.) 175.) Autoboxing/unboxing /unboxing — Conversiones automáticas entre tipos o Autoboxing primitivos (Como los int) y clases de envoltura primitivas (Como por JSR 201.) 201.) Integer). (Especificado por JSR typesafe,, lista o Enumeraciones — la palabra reservada enum crea una typesafe ordenada de valores (como Dia.LUNES, Dia.MARTES , etc.). Anteriormente, esto solo podía ser llevado a cabo por constantes enteras o clases construidas manualmente (enum pattern). (Especificado por JSR por JSR 201.) 201 .) o Varargs (número de argumentos variable) — El último parámetro de un método puede ser declarado con el nombre del tipo seguido por tres
puntos (e.g. void drawtext(String... lines)). En la llamada al método, puede usarse cualquier número de parámetros de ese tipo, que serán almacenados en un array para pasarlos al método. o Bucle for mejorado — La sintaxis para el bucle for se ha extendido con una sintaxis especial para iterar sobre cada miembro de un array o sobre cualquier clase que implemente Iterable , como la clase estándar Collection , de la siguiente forma: void displayWidgets (Iterable
Iterable widgets) widgets) { for (Widget w : widgets) widgets) { w.display w.display() (); ; } }
Este ejemplo itera sobre el objeto Iterable widgets, asignando, en orden, cada uno de los elementos a la variable w, y llamando al método display() de cada uno de ellos. (Especificado por JSR 201.) |} •
•
•
[5]
2006)) — Nombre clave Mustang . Estuvo en Java SE 6 (11 de diciembre de 2006 desarrollo bajo la JSR 270. 270. En esta versión, Sun cambió el nombre "J2SE" por versión.[4].. Está disponible en Java SE y eliminó el ".0" del número de versión.[4] http://java.sun.com/javase/6/.. Los cambios más importantes introducidos en esta http://java.sun.com/javase/6/ versión son: o Incluye un nuevo marco de trabajo y APIs que hacen posible la combinación de Java con lenguajes dinámicos como PHP, Python, Ruby y JavaScript. o Incluye el motor Rhino, de Mozilla, una implementación de Javascript en Java. o Incluye un cliente completo de Servicios Web y soporta las últimas especificaciones para Servicios Web, como JAX-WS 2.0, JAXB 2.0, STAX y JAXP. o Mejoras en la interfaz gráfica y en el rendimiento. Java SE 7 — Nombre clave Dolphin. En el año 2006 aún se encontraba en las primeras etapas de planificación. plan ificación. Se espera que su desarrollo dé comienzo en la primavera de 2006, y se estima es tima su lanzamiento para 2008. 20 08. o Soporte para XML dentro del propio lenguaje. o Un nuevo concepto de superpaquete. o Soporte para closures. o Introducción de anotaciones estándar para detectar fallos en el software. No oficiales: o NIO2 o Java Module System. o Java Kernel. Fechas , la cual reemplazara las o Nueva API para el manejo de Dias y Fechas, antiguas clases Date y Calendar. o Posibilidad de operar con clases BigDecimal usando operandos.
Además de los cambios en el lenguaje, con el paso de los años se han efectuado muchos más cambios dramáticos en la librería de clases de Java Java (Java class library) que ha crecido de unos pocos cientos de clases en JDK 1.0 hasta más de tres mil en J2SE 5.0. APIs completamente nuevas, como Swing y Java2D Java2D,, han sido introducidas y muchos de los métodos y clases originales de JDK 1.0 están obsoletas. En el 2005 se calcula en 4,5 millones el número de desarrolladores y 2.500 millones de dispositivos habilitados con tecnología Java. Entre noviembre de 2006 y mayo de 2007 2007,, Sun Microsystems liberó la mayor parte de sus tecnologías Java bajo la Licencia pública general de GNU, GNU, de acuerdo con las especificaciones del Java Community Process, de tal forma que prácticamente todo el Java de Sun es ahora software libre (aunque la biblioteca la biblioteca de clases de Sun que se requiere para ejecutar los programas Java todavía no es software libre). libre).
Filosofía [editar editar]] El lenguaje Java se creó con cinco objetivos principales: 1. Debería Debería usar usar la metodolog metodología ía de la programa programación ción orient orientada ada a objetos. objetos. 2. Debería permitir permitir la ejecución ejecución de un mismo mismo programa programa en en múltiples múltiples sistemas sistemas operativos. 3. Debería Debería inclui incluirr por defect defecto o soporte soporte para para trabajo trabajo en red. red. 4. Debería diseñarse para ejecutar código en en sistemas sistemas remotos de forma forma segura. segura. 5. Debería ser fácil fácil de usar usar y tomar tomar lo mejor de de otros lenguajes lenguajes orientados orientados a objetos, como C++. Para conseguir la ejecución de código remoto y el soporte de red, los programadores de Java a veces recurren a extensiones como CORBA (Common Object Request Broker Architecture), Internet Communications Engine o OSGi respectivamente. editar]] Orientado a Objetos [editar
La primera característica, orientado a objetos (“OO”), se refiere a un método de programación y al diseño dis eño del lenguaje. Aunque Aunqu e hay muchas interpretaciones interpretacio nes para OO, una primera idea es diseñar el software de forma que los distintos tipos de datos que use estén unidos a sus operaciones. Así, los datos y el código (funciones o métodos) se combinan en entidades llamadas objetos objetos.. Un objeto puede verse como un paquete que contiene el “comportamiento” (el código) y el “estado” (datos). El principio es separar aquello que cambia de las cosas que permanecen inalterables. Frecuentemente, cambiar una estructura de datos implica un cambio en el código que opera sobre los mismos, o viceversa. Esta separación en objetos coherentes e independientes ofrece una base más estable para el diseño de un sistema software. El objetivo es hacer que grandes proyectos sean fáciles de gestionar y manejar, mejorando mejora ndo como consecuencia consecuen cia su calidad y reduciendo el número de proyectos fallidos. Otra de las grandes promesas de la programación orientada orientad a a objetos es la creación creació n de entidades más genéricas ge néricas (objetos) que permitan la reutilización del software entre proyectos, una de las premisas fundamentales de la Ingeniería del Software. Un objeto genérico “cliente”, por ejemplo, debería en teoría tener el mismo conjunto de comportamiento en diferentes proyectos,
sobre todo cuando estos coinciden en cierta medida, algo que suele suceder en las grandes organizaciones. En este sentido, los objetos podrían verse como piezas reutilizables que pueden emplearse en múltiples proyectos distintos, posibilitando así a la industria del software a construir proyectos de envergadura empleando componentes ya existentes y de comprobada calidad; conduciendo esto finalmente a una reducción drástica del tiempo de desarrollo. Podemos usar como ejemplo de objeto el aluminio. Una vez definidos datos (peso, maleabilidad, etc.), y su “comportamiento” (soldar dos piezas, etc.), el objeto “aluminio” “alu minio” puede ser reutilizado reutiliz ado en el campo de la construcción, con strucción, del automóvil, de la aviación, etc. La reutilización del software ha experimentado resultados dispares, encontrando dos dificultades principales: el diseño de objetos realmente genéricos es pobremente comprendido, y falta una metodología para la amplia comunicación de oportunidades de reutilización. Algunas comunidades de “código abierto” (open source) quieren ayudar en este problema dando medios a los desarrolladores para diseminar la información sobre el uso y versatilidad de objetos reutilizables y librerías de objetos. editar]] Independencia de la plataforma plataforma [editar
La segunda característica, la independencia de la plataforma, significa que programas escritos en el lenguaje Java pueden ejecutarse igualmente en cualquier tipo de hardware. Es lo que significa ser capaz de escribir un programa una vez y que pueda ejecutarse en cualquier dispositivo, tal como reza el axioma de Java, ‘’’write once, run everywhere’’’. Para ello, se compila el código fuente escrito en lenguaje Java, para generar un código conocido como “bytecode” (específicamente Java bytecode)—instrucciones máquina simplificadas específicas de la plataforma Java. Esta pieza está “a medio camino” entre el código fuente y el código máquina que entiende el dispositivo destino. El bytecode es ejecutado entonces en la máquina virtual (VM), un programa escrito en código nativo de la plataforma destino (que es el que entiende su hardware), que interpreta y ejecuta el código. Además, se suministran librerías adicionales para acceder a las características de cada dispositivo (como los gráficos, ejecución mediante hebras o threads, la interfaz de red) de forma unificada. Se debe tener presente que, aunque hay una etapa explícita de compilación, el bytecode generado es interpretado o convertido a instrucciones máquina del código nativo por el compilador JIT (Just In Time). Hay implementaciones del compilador de Java que convierten el código fuente directamente en código objeto nativo, como GCJ GCJ.. Esto elimina la etapa intermedia donde se genera el bytecode, pero la salida de este tipo de compiladores sólo puede ejecutarse en un tipo de arquitectura. La licencia sobre Java de Sun insiste que todas las implementaciones sean “compatibles”. Esto dio lugar a una disputa legal entre Microsoft y Sun, cuando éste último alegó que la implementación de Microsoft no daba soporte a las interfaces RMI y JNI además de haber añadido características ‘’dependientes’’ de su plataforma. Sun demandó a Microsoft y ganó por daños y perjuicios (unos 20 millones de dólares) así como una orden judicial forzando la acatación de la licencia de Sun. Como respuesta, Microsoft no ofrece Java con su versión de sistema operativo, y en recientes versiones de Windows, su navegador Internet Explorer no admite la ejecución de applets sin un
conector (o plugin) aparte. Sin embargo, Sun y otras fuentes ofrecen versiones gratuitas para distintas versiones vers iones de Windows. Las primeras implementaciones del lenguaje usaban una máquina virtual interpretada para conseguir la portabilidad. po rtabilidad. Sin embargo, el resultado res ultado eran programas que se ejecutaban comparativamente más lentos que aquellos escritos en C o C++. Esto hizo que Java se ganase una reputación de lento en rendimiento. Las implementaciones recientes de la JVM dan lugar a programas que se ejecutan considerablemente más rápido que las versiones antiguas, empleando diversas técnicas, aunque sigue siendo mucho más lento que otros lenguajes. La primera de estas técnicas es simplemente compilar directamente en código nativo como hacen los compiladores tradicionales, eliminando la etapa del bytecode. Esto da lugar a un gran rendimiento en la ejecución, pero tapa el camino a la portabilidad. Otra técnica, conocida como compilación JIT (Just In Time, o ‘’’compilación al vuelo’’’), convierte el bytecode a código nativo cuando se ejecuta la aplicación. Otras máquinas virtuales más sofisticadas usan una ‘’’recompilación dinámica’’’ en la que la VM es capaz de analizar el comportamiento del programa en ejecución y recompila y optimiza las partes críticas. La recompilación dinámica puede lograr mayor grado de optimización que la compilación tradicional (o estática), ya que puede basar su trabajo en el conocimiento que de primera mano tiene sobre el entorno de ejecución y el conjunto de clases cargadas en memoria. La compilación JIT y la recompilación dinámica permiten a los programas Java aprovechar la velocidad de ejecución del código nativo sin por ello perder la ventaja de la portabilidad. La portabilidad es técnicamente difícil de lograr, y el éxito de Java en ese campo ha sido dispar. Aunque es de hecho posible escribir programas para la plataforma Java que actúen de forma correcta en múltiples plataformas de distinta arquitectura, el gran número de estas con pequeños errores o inconsistencias llevan a que a veces se parodie el eslogan de Sun, "Write "Write once, run anywhere" anywhere" como "Write once, debug everywhere" (o “Escríbelo una vez, ejecútalo en cualquier parte” por “Escríbelo una vez, depúralo en todas partes”) El concepto de independencia de la plataforma de Java cuenta, sin embargo, con un gran éxito en las aplicaciones en el entorno del servidor, como los Servicios Web, los Servlets, los Java Beans, así como en sistemas empotrados basados en OSGi OSGi,, usando entornos Java empotrados. editar]] El recolector de basura [editar
Un argumento en contra de lenguajes como C++ es que los programadores se encuentran con la carga añadida de tener que administrar la memoria solicitada dinámicamente de forma manual: En C++, el desarrollador puede asignar memoria en una zona conocida como heap (montículo montículo)) para crear cualquier objeto, y posteriormente desalojar el espacio asignado cuando desea borrarlo. Un olvido a la hora de desalojar memoria previamente solicitada puede llevar a una fuga de memoria, ya que el sistema operativo seguirá pensando que esa zona de memoria está siendo usada por una aplicación cuando en realidad no es así. Así, un programa mal diseñado podría consumir una cantidad desproporcionada de
memoria. Además, si una misma región de memoria es desalojada dos veces el programa puede volverse volv erse inestable y llevar a un eventual cuelgue. No obstante, se debe señalar que C++ también permite crear objetos en la pila la pila de llamadas de una función o bloque, de forma que se libere libe re la memoria (y se ejecute el destructor del objeto) de forma automática al finalizar la ejecución de la función o bloque. En Java, este problema potencial es evitado en gran medida por el recolector automático de basura (o automatic garbage collector ). ). El programador determina cuándo se crean los objetos y el entorno en tiempo de ejecución de Java (Java runtime) es el responsable de gestionar el ciclo de vida de los objetos. El programa, u otros objetos pueden tener localizado un objeto mediante una referencia a éste (que, desde un punto de vista de bajo nivel es una dirección direcc ión de memoria). Cuando no quedan referencias a un objeto, el recolector de basura de Java borra el objeto, liberando así la memoria que ocupaba previniendo posibles pos ibles fugas (ejemplo: un objeto creado y únicamente única mente usado dentro de un método sólo tiene entidad dentro de éste; al salir del método el objeto es eliminado). Aun así, es posible que se produzcan fugas de memoria si el código almacena referencias a objetos que ya no son necesarios—es decir, pueden aún ocurrir, pero en un nivel conceptual superior. En definitiva, el recolector de basura de Java permite una fácil creación y eliminación de objetos, mayor seguridad y puede que más rápida que en C++ [cita requerida]. La recolección de basura de Java es un proceso prácticamente invisible al desarrollador. Es decir, el programador no tiene conciencia de cuándo la recolección de basura tendrá lugar, ya que ésta no tiene necesariamente que guardar relación con las acciones que realiza el código fuente. Debe tenerse en cuenta que la memoria es sólo uno de los muchos recursos que deben ser gestionados. editar]] Sintaxis [editar
La sintaxis de Java se deriva en gran medida de C++ C++.. Pero a diferencia de éste, que combina la sintaxis para programación genérica, estructurada y orientada a objetos, Java fue construido desde el principio para ser completamente orientado a objetos. Todo en Java es un objeto (salvo algunas excepciones), y todo en Java reside en alguna clase (recordemos que una clase es un molde a partir del cual pueden crearse varios objetos). editar]] Hola Mundo [editar Artículo principal: Hola mundo
Aplicaciones autónomas [editar [editar]] // Hola.java
public class Hola { public static void main( main(String [] args) args) { .out out. .println println( ("Hola, mundo!") mundo!"); System } }
Este ejemplo necesita una pequeña explicación. • •
•
•
• •
•
•
•
•
Todo en Java está dentro de una clase, incluyendo programas autónomos. El código fuente se guarda en archivos con el mismo nombre que la clase que contienen y con extensión “.java”. Una clase (class) declarada pública (public) debe seguir este convenio. En el ejemplo anterior, la clase es Hola, por lo que el código fuente debe guardarse en el fichero “Hola.java” El compilador genera un archivo de clase (con extensión “.class”) por cada una de las clases definidas en el archivo fuente. Una clase anónima se trata como si su nombre fuera la concatenación del nombre de la clase que la encierra, el símbolo “$”, y un número entero. Los programas que se ejecutan de forma independiente y autónoma, deben contener el método ”main()” . La palabra reservada ”void” indica que el método main no devuelve nada. El método main debe aceptar un array de objetos tipo String. Por acuerdo se referencia como ”args”, aunque puede emplearse cualquier otro identificador. La palabra reservada ”static” indica que el método es un método de clase, clase, asociado a la clase en vez de a instancias de la misma. El método main debe ser estático o ’’de clase’’. La palabra reservada public significa que un método puede ser llamado desde otras clases, o que la clase puede ser usada por clases fuera de la jerarquía de la propia clase. Otros tipos de d e acceso son ”private” o ”protected”. La utilidad de impresión (en pantalla por ejemplo) forma parte de la librería estándar de Java: la clase ‘’’System’’’ define un campo público estático llamado ‘’’out’’’. El objeto out es una instancia de ‘’’PrintStream’’’, que ofrece el método ‘’’println(String)’’’ para volcar datos en la pantalla (la salida estándar). Las aplicaciones autónomas se ejecutan dando al entorno de ejecución de Java el nombre de la clase cuyo método main debe invocarse. Por ejemplo, una línea de comando (en Unix o Windows Windows)) de la forma java –cp . Hola ejecutará el programa del ejemplo (previamente (p reviamente compilado y generado ge nerado “Hola.class”) . El nombre de la clase cuyo método main se llama puede especificarse también en el fichero “MANIFEST” del archivo de empaquetamiento de Java (.jar).
Applets [editar [editar]]
Las applets de Java son programas incrustados en otras aplicaciones, normalmente una página Web que se muestra en un navegador. // Hola.java
import java.applet.Applet; import java.awt.Graphics; public class Hola extends Applet extends Applet { paint(Graphics gc) gc) { public void paint( gc.drawString gc.drawString( ("Hola, mundo!", mundo!", 65 65, , 95 95) ); } }
Applet Hola Mundo Applet
code= ="Hola" width width= ="200" height height= ="200">
La sentencia import indica al compilador de Java que incluya las clases java.applet. Applet y java.awt. Graphics, para poder referenciarlas por sus nombres, sin tener que anteponer la ruta completa cada vez que se quieran usar en el código fuente. La clase Hola extiende (extends) a la clase Applet, es decir, es una subclase de ésta. La clase Applet permite a la aplicación mostrar y controlar el estado del applet. La clase Applet es un componente del AWT (Abstract Windowing Toolkit), que permite al applet mostrar una inteterfaz gráfica de usuario o GUI (Graphical User Interface), y responder a eventos generados por el usuario. La clase Hola sobrecarga el método paint(Graphics) heredado de la superclase contenedora (Applet en este caso), para acceder al código encargado de dibujar. El método paint() recibe un objeto Graphics que contiene el contexto gráfico para dibujar el applet. El método paint() llama al método drawString(String, int, int) del objeto Graphics para mostrar la cadena de caracteres Hola, mundo! en la posición (65, 96) del espacio de dibujo asignado al applet. La referencia al applet es colocada en un documento HTML usando la etiqueta . Esta etiqueta o tag tiene tres atributos: code="Hola" indica el nombre del applet, y width="200" height="200" height="200" establece la anchura y altura, respectivamente, del applet. Un applet también pueden alojarse dentro de un documento HTML usando los elementos object, o embed, aunque el soporte que ofrecen los navegadores Web no es uniforme.[6] uniforme.[6][7] [7] Servlets [editar [editar]]
Los servlets son componentes de la parte del servidor de Java EE, encargados de generar respuestas a las peticiones recibidas de los clientes. // Hola.java
import java.io.*; import javax.servlet.*; public class Hola extends GenericServlet { service(ServletRequest ServletRequest request, ServletResponse public void service( response) response) throws ServletException, IOException { response.setContentType response.setContentType( ("text/html" "text/html") ); response.getWriter() (); ; PrintWriter pw = response.getWriter pw.println pw.println( ("Hola, mundo!") mundo!"); pw.close pw.close() (); ; } }
Las sentencias import indican al compilador de Java la inclusión de todas las clases públicas e interfaces de los paquetes java.io y javax.servlet en la compilación. La clase Hola extiende (extends), es heredera de la clase GenericServlet. Esta clase proporciona la interfaz inter faz para que el servidor servid or le pase las peticiones al servlet y el mecanismo para controlar el ciclo de vida del servlet. La clase Hola sobrecarga el método service(ServletRequest, ServletResponse), definido por la interfaz servlet para acceder al manejador de la petición de servicio. El método service() recibe un objeto de tipo ServletRequest que contiene la petición del cliente y un objeto de tipo ServletResponse, usado para generar la respuesta que se devuelve al cliente. El método service() puede lanzar (throws) excepciones de tipo ServletException e IOException si ocurre algún tipo de anomalía. El método setContentType(String) en el objeto respuesta establece el tipo de contenido MIME a "text/html", para indicar al cliente que la respuesta a su petición es una página con formato HTML. El método getWriter() del objeto respuesta devuelve un objeto de tipo PrintWriter, usado como una tubería por la que viajarán los datos al cliente. El método println(String) escribe la cadena "Hola, mundo!" en la respuesta y finalmente se llama al método close() para cerrar la conexión, que hace que los datos escritos en la tubería o stream sean devueltos al cliente. Aplicaciones con ventanas [editar [editar]]
Swing es la librería para la interfaz gráfica de usuario avanzada de la plataforma Java SE. // Hola.java
import javax.swing.*; public class Hola extends JFrame { Hola() Hola() { setDefaultCloseOperation WindowConstants ( WindowConstants.DISPOSE_ON_CLOSE ); add( add(new JLabel("Hola, mundo!")) mundo!")); ; pack() pack(); ; }
main(String[] args) args) { public static void main( Hola(). .setVisible setVisible( (true); new Hola() } }
Las instrucciones import indican al compilador de Java que las clases e interfaces del paquete javax.swing se incluyan en la compilación. La clase Hola extiende (extends) la clase javax.swing.JFrame, que implementa una ventana con una barra de título y un control para cerrarla. El constructor Hola() inicializa el marco o frame llamando al método setDefaultCloseOperation(int) heredado de JFrame para establecer las operaciones por defecto cuando el control de cierre en la barra de título es seleccionado al valor WindowConstants.DISPOSE_ON_CLOSE. Esto hace que se liberen los recursos
tomados por la ventana cuando es cerrada, y no simplemente ocultada, lo que permite a la máquina virtual y al programa acabar su ejecución. A continuación se crea un objeto de tipo JLabel con el texto "Hola, mundo!", y se añade al marco mediante el método add(Component), heredado de la clase Container. El método pack(), heredado de la clase Window, es invocado para dimensionar la ventana y distribuir su contenido. El método main() es llamado por la JVM al comienzo del programa. Crea una instancia de la clase Hola y hace la ventana sea mostrada invocando al método setVisible(boolean) de la superclase (clase de la que hereda) con el parámetro a true. Véase que, una vez el marco es dibujado, el programa no termina cuando se sale del método main(), ya que el código del que depende se encuentra en un hilo de ejecución independiente ya lanzado, y que permanecerá activo hasta que todas las ventanas hayan sido destruidas.
Entornos de funcionamiento
[editar editar]]
El diseño de Java, su robustez, el respaldo de la industria y su fácil portabilidad han hecho de Java uno de los lenguajes con un mayor crecimiento y amplitud de uso en distintos ámbitos de la industria de la informática. editar]] En dispositivos móviles y sistemas empotrados [editar
Desde la creación de la especificación J2ME (Java 2 Platform, Micro Edition), una versión del entorno de ejecución Java reducido y altamente optimizado, especialmente desarrollado para el mercado de dispositivos electrónicos de consumo se ha producido toda una revolución en lo que a la extensión de Java se refiere. Es posible encontrar microprocesadores específicamente diseñados para ejecutar bytecode Java y software so ftware Java para tarjetas inteligentes inte ligentes (JavaCard), teléfonos te léfonos móviles, buscapersonas, set-top-boxes, se t-top-boxes, sintonizadores sintonizad ores de TV y otros pequeños pequeñ os electrodomésticos. El modelo de desarrollo de estas aplicaciones es muy semejante a las applets de los navegadores salvo que en este caso se denominan MIDlets. Véase Sun Mobile Device Tecnology editar]] En el navegador web [editar
Desde la primera versión de java existe la posibilidad de desarrollar pequeñas aplicaciones (Applets (Applets)) en Java que luego pueden ser incrustadas en una página HTML para que sean descargadas desca rgadas y ejecutadas por p or el navegador web. Estas mini-aplicaciones mini-a plicaciones se ejecutan en una JVM que el navegador tiene configurada como extensión plug-in (plug-in) en un contexto de seguridad restringido configurable para impedir la ejecución local de código potencialmente malicioso. El éxito de este tipo de aplicaciones (la visión del equipo de Gosling) no fue realmente el esperado debido a diversos factores, siendo quizás el más importante la lentitud y el reducido ancho de banda de las comunicaciones en aquel entonces que limitaba el
tamaño de las applets que se incrustaban en el navegador. La aparición posterior de otras alternativas (aplicaciones web dinámicas de servidor) dejó un reducido ámbito de uso para esta tecnología, quedando hoy relegada fundamentalmente a componentes específicos para la intermediación desde una aplicación web dinámica de servidor con dispositivos ubicados en la máquina cliente donde se ejecuta el navegador. Las applets Java no son las únicas tecnologías (aunque sí las primeras) de componentes complejos incrustados en el navegador. Otras tecnologías similares pueden ser:ActiveX ser: ActiveX de Microsoft, Flash Flash,, Java Web Start, Start, etc. editar]] En sistemas de servidor [editar
En la parte del servidor, Java es más popular que nunca, desde la aparición de la especificación de Servlets y JSP (Java (Java Server Pages). Pages). Hasta entonces, las aplicaciones web dinámicas de servidor que existían se basaban fundamentalmente en componentes CGI y lenguajes interpretados. Ambos tenían diversos inconvenientes (fundamentalmente lentitud, elevada carga computacional o de memoria y propensión a errores por su interpretación dinámica). Los servlets y las JSPs supusieron un importante avance ya que: •
•
•
El API de programación es muy sencilla, flexible y extensible. Los servlets no son procesos independientes (como los CGIs) y por tanto se ejecutan dentro del mismo proceso que la JVM mejorando notablemente el rendimiento y reduciendo la carga computacional y de memoria requeridas. Las JSPs son páginas que se compilan dinámicamente (o se pre-compilan previamente a su distribución) distrib ución) de modo que el código có digo que se consigue consigu e una ventaja en rendimiento substancial frente a muchos lenguajes interpretados.
La especificación de Servlets y JSPs define un API de programación y los requisitos para un contenedor (servidor) dentro del d el cual se puedan desplegar desp legar estos componentes componente s para formar aplicaciones aplicacion es web dinámicas completas. Hoy día existen multitud de contenedores (libres y comerciales) compatibles con estas especificaciones. A partir de su expansión entre la comunidad de desarrolladores, estas tecnologías han dado paso a modelos de desarrollo mucho más elaborados con frameworks (pe Struts Struts,, Webwork ) que se sobreponen sobre los servlets y las JSPs para conseguir un entorno de trabajo mucho más poderoso y segmentado en el que la especialización de roles sea posible (desarrolladores, (desarrollad ores, diseñadores gráficos, ...) y se facilite la reutilización reutiliz ación y robustez de código. A pesar de todo ello, las tecnologías que subyacen (Servlets y JSPs) son substancialmente las mismas. Este modelo de trabajo se ha convertido en un estándar de-facto para el desarrollo de aplicaciones web dinámicas de servidor y otras tecnologías (pe. ASP ASP)) se han basado en él. editar]] En aplicaciones de escritorio [editar
Hoy en día existen multitud de aplicaciones gráficas de usuario basadas en Java. El entorno de ejecución Java (JRE) se ha convertido en un componente habitual en los PCs de usuario de los sistemas operativos más usados en el mundo. Además, muchas aplicaciones Java lo incluyen dentro del propio paquete de la aplicación de modo que se ejecuten en cualquier PC cualquier PC.. En las primeras versiones de la plataforma Java existían importantes limitaciones en las APIs de desarrollo gráfico (AWT (AWT). ). Desde la aparición de la librería Swing la situación mejoró substancialmente y posteriormente con la aparición de librerías comoSWT como SWT hacen que el desarrollo de aplicaciones de escritorio complejas y con gran dinamismo, usabilidad, etc. sea relativamente sencillo.
editar]] Plataformas soportadas [editar
Una versión del entorno de ejecución Java JRE (Java Runtime Environment) está disponible en la mayoría de equipos de escritorio. Sin embargo, Microsoft no lo ha incluido por defecto en sus sistemas operativos. En el caso de Apple Apple,, éste incluye una versión propia del JRE en su sistema operativo, el Mac OS. OS. También es un producto que por defecto aparece en la mayoría de las distribuciones distrib uciones de Linux Linux.. Debido a incompatibilidades entre distintas versiones del JRE, muchas aplicaciones prefieren instalar su propia copia del JRE antes que confiar su suerte a la aplicación instalada por defecto. Los desarrolladores de applets de Java o bien deben insistir a los usuarios en la actualización del JRE, o bien desarrollar bajo una versión antigua de Java y verificar el correcto funcionamiento en las versiones posteriores. editar]] Industria relacionada [editar
Sun Microsystem, como creador del lenguaje de programación Java y de la plataforma JDK, mantiene fuertes políticas para mantener una especificación del lenguaje1 así como de la máquina virtual2 a través del JCP. Es debido a este esfuerzo que se mantiene un estándar de facto. Son innumerables las compañías que desarrollan aplicaciones para Java y/o están volcadas con esta tecnología: •
•
•
•
La industria de la telefonía móvil está fuertemente influenciada por la tecnología Java. El entorno de desarrollo Eclipse ha tomado un lugar importante entre la comunidad de desarrolladores Java. La fundación Apache tiene también una presencia importante en el desarrollo de librerías y componentes de servidor basados en Java. IBM,, BEA IBM BEA,, IONA IONA,, Oracle Oracle,... ,... son empresas con grandes intereses y productos creados en y para Java.
editar]] Críticas [editar
Harold dijo en 1995 que Java fue creado para abrir una nueva vía en la gestión de software complejo, y es por regla general aceptado que se ha comportado bien en ese aspecto. Sin embargo no puede decirse que Java no tenga grietas, ni que se adapta completamente a todos los estilos de programación, todos los entornos, o todas las necesidades. editar]] General [editar •
Java no ha aportado capacidades estándares para aritmética en punto flotante. El estándar IEEE estándar IEEE 754 para “Estándar para Aritmética Binaria en Punto Flotante” apareció en 1985, y desde entonces es el estándar para la industria. Y aunque la aritmética flotante de Java (cosa que cambió desde el 13 de Noviembre de 2006, cuando se abrió el código fuente y se adoptó la licencia GNU, aparte de la ya existente) se basa en gran medida en la norma del IEEE, no soporta aún algunas características. Más información al respecto puede encontrarse en la sección final de enlaces externos.
editar]] El lenguaje [editar •
•
•
En un sentido estricto, Java no es un lenguaje absolutamente orientado a objetos, a diferencia de, por ejemplo, Ruby o Smalltalk . Por motivos de eficiencia, Java ha relajado en cierta medida el paradigma de orientación a objetos, y así por ejemplo, no todos los valores son objetos. El código Java puede ser a veces redundante en comparación con otros lenguajes. Esto es en parte debido a las frecuentes declaraciones de tipos y conversiones de tipo manual (casting). También se debe a que no se dispone de operadores sobrecargados, y a una sintaxis relativamente simple. Sin embargo, J2SE 5.0 introduce elementos para tratar de reducir la redundancia, como una nueva construcción para los bucles ‘’’foreach’’’. A diferencia de C++, Java no dispone de operadores de sobrecarga definidos por el usuario. Sin embargo esta fue una decisión de diseño que puede verse como una ventaja, ya que esta característica puede hacer los programas difíciles de leer y mantener.
editar]] Apariencia [editar
La apariencia externa (el ‘’’look and feel’’’) de las aplicaciones GUI (Graphical User Interface) escritas en Java usando la plataforma Swing difiere a menudo de la que muestran aplicaciones nativas. Aunque el programador puede usar el juego de herramientas AWT (Abstract Windowing Toolkit) que genera objetos gráficos de la plataforma nativa, el AWT no es capaz de funciones gráficas gráfica s avanzadas sin sacrificar sa crificar la portabilidad entre entr e plataformas; ya que cada cad a una tiene un conjunto de APIs distinto, especialmente para objetos gráficos de alto nivel. Las herramientas de Swing, escritas completamente en Java, evitan este problema construyendo los objetos gráficos a partir de los mecanismos de dibujo básicos que deben estar disponibles en todas las plataformas. El inconveniente inconvenien te es el trabajo extra requerido r equerido para conseguir cons eguir la misma apariencia de la plataforma destino. Aunque esto es posible (usando GTK+ y el Lookand-Feel de Windows), la mayoría de los usuarios no saben cómo cambiar la apariencia que se proporciona por defecto por aquella que se adapta a la de la plataforma.
editar]] Rendimiento [editar
El rendimiento de una aplicación está determinado por multitud de factores, por lo que no es fácil hacer una comparación que resulte totalmente objetiva. En tiempo de ejecución, el rendimiento de una aplicación Java depende más de la eficiencia del compilador, o la JVM, que de las propiedades intrínsecas del lenguaje. El bytecode de Java puede ser interpretado en tiempo de ejecución por la máquina virtual, o bien compilado al cargarse el programa, o durante la propia ejecución, para generar código nativo que se ejecuta directamente sobre el hardware. Si es interpretado, será más lento que usando el código máquina intrínseco de la plataforma destino. Si es compilado, durante la carga inicial o la ejecución, la penalización está en el tiempo necesario para llevar a cabo la compilación. Algunas características del propio lenguaje conllevan una penalización en tiempo, aunque no son únicas de Java. Algunas de ellas son el chequeo de los límites de arrays, chequeo en tiempo de ejecución de tipos, y la indirección de funciones virtuales. virtuales. El uso de un recolector de basura para eliminar de forma automática aquellos objetos no requeridos, añade una sobrecarga que puede afectar al rendimiento, o ser apenas apreciable, dependiendo de la tecnología del recolector y de la aplicación en concreto. Las JVM modernas usan recolectores de basura que gracias a rápidos algoritmos de manejo de memoria, consiguen que algunas aplicaciones puedan ejecutarse más eficientemente. El rendimiento entre un compilador JIT y los compiladores nativos puede ser parecido, aunque la distinción no está clara en este punto. La compilación mediante el JIT puede consumir un tiempo apreciable, un inconveniente principalmente para aplicaciones de corta duración o con gran cantidad de código. Sin embargo, una vez compilado, el rendimiento del programa puede ser comparable al que consiguen compiladores nativos de la plataforma destino, inclusive en tareas numéricas. Aunque Java no permite la expansión manual de llamadas a métodos, muchos compiladores JIT realizan esta optimización durante la carga de la aplicación y pueden aprovechar información del entorno en tiempo de ejecución para llevar a cabo transformaciones eficientes durante la propia ejecución de d e la aplicación. Esta recompilación recompilac ión dinámica, como la que qu e proporciona la máquina máquin a virtual HotSpot de Sun, puede pued e llegar a mejorar el resultado resultad o de compiladores estáticos tradicionales, gracias a los datos que sólo están disponibles durante el tiempo de ejecución. Java fue diseñado para ofrecer seguridad y portabilidad, y no ofrece acceso directo al hardware de la arquitectura ni al espacio de direcciones. Java no soporta expansión de código ensamblador, aunque las aplicaciones pueden acceder a características de bajo nivel usando librerías nativas (JNI, Java Native Interfaces). editar]] Recursos [editar editar]] JRE [editar
El JRE (Java Runtime Environment, o Entorno en Tiempo de Ejecución de Java) es el software necesario para ejecutar cualquier aplicación desarrollada para la plataforma
Java. El usuario final usa el JRE como parte de paquetes software o plugins (o conectores) en un navegador Web. Sun ofrece también el SDK de Java 2, o JDK (Java Development Kit) en cuyo seno reside el JRE, e incluye herramientas como el compilador de Java, Javadoc para generar documentación o el depurador . Puede también obtenerse como un paquete independiente, y puede considerarse como el entorno necesario para ejecutar una aplicación Java, mientras que un desarrollador debe además contar con otras facilidades que ofrece el JDK. editar]] Componentes [editar •
Bibliotecas de Java, que son el resultado de compilar el código fuente desarrollado por quien implementa la JRE, y que ofrecen apoyo para el desarrollo en Java. Algunos ejemplos de estas librerías son: o Las bibliotecas centrales, que incluyen: Una colección de bibliotecas para implementar estructuras implementar estructuras de datos como listas listas,, arrays, árboles y conjuntos. Bibliotecas para análisis de XML XML.. Seguridad. Bibliotecas de internacionalización y localización. o Bibliotecas de integración, que permiten la comunicación con sistemas externos. Estas librerías incluyen: La API para acceso a bases de datos JDBC (Java DataBase Conectivity). La interfaz JNDI (Java Naming and Directory Interface) para servicios de directorio. RMI (Remote Method Invocation) y CORBA para el desarrollo de aplicaciones distribuidas. o Bibliotecas para la interfaz de usuario, que incluyen: El conjunto de herramientas nativas AWT (Abstract Windowing Toolkit), que ofrece componentes GUI (Graphical User Interface), mecanismos para usarlos y manejar sus eventos asociados. Las Bibliotecas de Swing, construidas sobre AWT pero ofrecen implementaciones no nativas de los componentes de AWT. APIs para la captura, procesamiento y reproducción de audio. Una implementación dependiente de la plataforma en que se ejecuta de la máquina virtual de Java (JVM), que es la encargada de la ejecución del código de las librerías y las aplicaciones externas. Plugins o conectores que permiten ejecutar applets en los navegadores Web. Java Web Start, para la distribución de aplicaciones Java a través de Internet. Documentación y licencia.
•
• • •
editar]] APIs [editar
Sun define tres plataformas en un intento por cubrir distintos entornos de aplicación. Así, ha distribuido muchas de sus APIs (Application Program Interface) de forma que pertenezcan a cada una de las plataformas:
•
•
•
Java ME (Java Platform, Micro Edition) o J2ME — orientada a entornos de limitados recursos, como teléfonos móviles, PDAs (Personal Digital Assistant), etc. Java SE (Java Platform, Standard Edition) o J2SE — para entornos de gama media y estaciones de trabajo. Aquí se sitúa al usuario medio en un PC de escritorio. Java EE (Java Platform, Enterprise Edition) o J2EE — orientada a entornos distribuidos empresariales o de Internet.
Las clases en las APIs de Java se organizan en grupos disjuntos llamados paquetes. Cada paquete contiene un conjunto de interfaces, clases y excepciones relacionadas. La información sobre los paquetes que ofrece cada plataforma puede encontrarse en la documentación de ésta. El conjunto de las APIs es controlado por Sun Microsystems junto con otras entidades o personas a través del programa JCP (Java Community Process). Process) . Las compañías o individuos participantes del JCP pueden influir de forma activa en el diseño y desarrollo de las APIs, algo que ha sido motivo de controversia. En 2004, IBM y BEA apoyaron públicamente la idea de crear una implementación de código abierto (open source) de Java, algo a lo que Sun, a fecha de 2006, se ha negado. editar]] Extensiones y arquitecturas relacionadas [editar
Las extensiones de Java están en paquetes que cuelgan de la raíz javax: javax.*. No se incluyen en la JDK o el JRE. Algunas de las extensiones y arquitecturas ligadas estrechamente al lenguaje Java son: •
•
• • • • • • • • • • • • • • • • •
Java EE (Java Platform, Enterprise Edition; antes J2EE) —para aplicaciones distribuidas orientadas al entorno empresarial Java ME (Java Platform, Micro Edition; antes J2ME)—para dispositivos de recursos limitados como teléfonos móviles y PDAs JMF (Java Media Framework) JavaHelp JavaMail JNDI (Java Naming and Directory Interface) JSML (Java Speech API Markup Language) JDBC (Java Database Connectivity) JDO (Java Data Objects) JAI (Java Advanced Imaging) JAIN (Java API for Integrated Networks) JDMK (Java JDMK (Java Dynamic Management Kit) Jini (una arquitectura de red para la construcción de sistemas distribuidos Jiro Java Card JavaSpaces JML (Java Modeling Language) JMI (Java Metadata Interface) JMX (Java Management Extensions)
• • • • • •
•
• •
JSP (JavaServer Pages) JSF (JavaServer Faces) JNI (Java Native Interface) JXTA (Protocolos abiertos para redes virtuales Peer-to-Peer o P2P) Java 3D (Una API de alto nivel para programación gráfica en 3D) JOGL (Java OpenGL—Una API de bajo nivel para programación gráfica usando OpenGL)) OpenGL LWJGL (Light Weight Java Game Library—Una API de bajo nivel para acceso a OpenGL OpenGL,, OpenAL y varios dispositivos de entrada) MARF (Modular Audio Recognition Framework) OSGi (Dynamic Service Management and Remote Maintenance)
editar]] Java en código abierto [editar
Java se ha convertido en un lenguaje con una implantación masiva en todos los entornos (personales y empresariales). El control que mantiene Sun sobre éste genera reticencias en la comunidad de empresas con fuertes intereses en Java (IBM (IBM,, Oracle Oracle)) y obviamente en la comunidad de desarrolladores de software libre. libre. La evolución basada en un comité en el que participen todos los implicados no es suficiente y la comunidad demandaba desde hace tiempo la liberación de las APIs y librerías básicas de la JDK. editar]] ¿Hasta donde Java es Software libre? libre? [editar
En diciembre de 2006, Sun está en pleno relanzamiento de su plataforma Java3 bajo la licencia GPL de GNU GNU.. editar]] Compromiso de Sun Microsystems con el código abierto [editar
La importancia del código abierto en relación con Java puede verse entre otras cosas, en que el presidente y CEO de Sun, Jonathan Schwartz, ha retado a la compañía a que ofrezca código abierto para todo el software que produce Sun (fuente) (fuente),, Sun ya hace mucho tiempo que empezó a apostar por el código abierto cuando liberó StarOffice (Llamado ahora OpenOffice OpenOffice). ). Sun ha aportado más líneas de código abierto que cualquier otra organización (fuente) También Richard Stallman opina eso mismo (fuente) •
El éxito del código abierto - Artículo puesto en el sito oficial en Español de Sun Microsystems, en el que habla de la apuesta de Sun Microsystems por el código abierto.
editar]] Alternativas libres [editar
Existen alternativas suficientemente maduras para el entorno de ejecución y de desarrollo de Java con una gran cobertura de funcionalidades con respecto a las implementaciones comerciales de Sun, IBM, Bea, ...
• •
•
Blackdown Java para Linux Linux,, incluye un plugin para Mozilla GNU Classpath de GNU - actualmente está siendo fusionado con libgcj del Compilador para Java de GNU Apache Harmony de Apache
editar]] Críticas referentes a Java y el software libre [editar •
Free But Shackled — The Java Trap, Trap, de Richard Stallman, Stallman, 12 de abril, abril, 2004 2004.. (respuesta de James Gosling) Gosling) o Traducción al Español de este artículo: Libre pero encadenado. La trampa del Java. (Nótese que hay una nota en un recuadro amarillo que habla de la situación actual con respecto a lo que se dice en ese artículo)
Notar que este artículo fue f ue escrito antes de la liberación libe ración del código fuente f uente de Java. En la actualidad la postura de la Free Software Foundation y de Richard Stallman han cambiado, mostrándose partidarios ambos por su uso en software libre. editar]] Software libre basado en Java [editar • • • • •
Azureus Eclipse Limewire iRATE Radio Java Source dispone de una lista de software libre (licencias GNU, LGNU, Apache, BSD, ...) hecho en Java.
editar]] Véase también [editar • • • • • • • • • • • • • • •
Java syntax Java keywords Java virtual machine Java platform Java applet Java Platform, Standard Edition (Java SE, J2SE) JavaOS Comparison of Java and C++ Comparison of C# and Java Java User Group Java Community Process JavaOne Join Java programming language Javapedia Inferno operating system
editar]] Referencias [editar •
Jon Byous, Java technology: The early years. Sun Developer Network, sin fecha[ca. 1998]. Recuperado 21 de abril de 2005.
•
•
•
James Gosling, Gosling, A brief history of the Green project . Java.net, sin fecha [ca. Q1/1998]. Recuperado 22 abril de 2005. James Gosling, Gosling, Bill Joy, Joy, Guy Steele, Steele, y Gilad Bracha, Bracha, The Java language 0-321-24678-0. specification, tercera edición. Addison-Wesley, 2005. ISBN 0-321-24678-0. Tim Lindholm y Frank Yellin. The Java Virtual Machine specification , segunda edición. Addison-Wesley, 1999. ISBN 0-201-43294-3. 0-201-43294-3.
Ejemplos De Programación Dinámica •
• • • • • • • • •
[editar editar]]
Ejecución de n tareas en tiempo mínimo en un sistema de dos procesadores A y B Programas en disco Problema de los sellos con programación dinámica Problema de la mochila con programación dinámica Problema del producto de una secuencia de matrices con programación dinámica Problema de las monedas con programación dinámica Camino de coste mínimo entre dos nodos de un grafo dirigido Problema de la división de peso Problema de las vacas con programación dinámica Problema del Cambio de Palabra Programación Dinámica en JAVA
Notas [editar editar]] 1. ↑ Especificación del lenguaje Java 2. ↑ Especificación de la máquina virtual Java 3. ↑ [1]
Enlaces externos [editar editar]] •
Wikilibros alberga un libro o manual sobre Programación en Java.
editar]] Sun [editar • •
• •
Sitio oficial de Java para desarrolladores, etc The Java Language Specification, Tercera edición Especificación oficial del lenguaje Java Tutorial de Sun sobre el Lenguaje de programación Java Libro blanco original de Java, Java, 1996
editar]] Tutoriales [editar • • • •
•
The Java Tutorial de Sun Microsystems (online) Thinking in Java , de Bruce Eckel (online) An introduction to Computer Science using Java por Bradley Kjell. Java Course, de A.B. Downey. Computer-Books.us Colección de libros sobre Java disponibles para descarga gratuita.
•
En castellano: o Tutorial de Java básico o Colección «Java a tope» de libros electrónicos (Universidad de Málaga. España) o Tutoriales de Java avanzados, básicos y preguntas de certificación para practicar.
editar]] Críticas [editar •
•
Softpanorama Java Critique Page: Java vs Scripting Languages, Languages, de Nikolai de Nikolai Bezroukov How Java’s Floating-Point Hurts Everyone Everywhere, Everywhere, de W. Kahan und Joseph D. Darcy en el ACM 1998 Workshop on Java for High–Performance Network Computing
Introducción a Java 1.1 Origen de Java Sun Microsystems, líder en servidores para Internet Internet,, uno de cuyos lemas desde hace mucho tiempo es "the network is the computer" (lo que quiere dar a entender que el verdadero ordenador es la red en su conjunto y no cada máquina individual), es quien ha desarrollado el lenguaje Java Java,, en un intento de resolver simultáneamente todos los problemas que se le plantean a los desarrolladores de software por la proliferación de arquitecturas incompatibles, tanto entre las diferentes máquinas como entre los diversos sistemas operativos y sistemas y sistemas de ventanas que funcionaban sobre una misma m isma máquina, añadiendo la dificultad de crear aplicaciones distribuidas en una red como Internet Internet.. He podido leer más de cinco versiones distintas sobre el origen, concepción y desarrollo de Java Java,, desde la que dice que este fue un proyecto que rebotó durante mucho tiempo por distintos departamentos de Sun sin que nadie le prestara ninguna atención, hasta que finalmente encontró su nicho de mercado en la aldea global que es Internet; Internet; hasta la más difundida, que justifica a Java como lenguaje de pequeños electrodomésticos. Hace algunos años, Sun Microsystems decidió intentar introducirse en el mercado de la electrónica de consumo y desarrollar programas para pequeños dispositivos electrónicos. Tras unos comienzos dudosos, Sun decidió crear una filial, denominada FirstPerson Inc., para dar margen de maniobra al equipo responsable del proyecto proyecto.. El mercado inicialmente previsto para los programas de FirstPerson eran los equipos domésticos: microondas microondas,, tostadoras y, fundamentalmente, televisión interactiva. Este mercado mercado,, dada la falta de pericia de los usuarios para el manejo de estos dispositivos, requería unos interfaces mucho más cómodos e intuitivos que los sistemas de ventanas que proliferaban en el momento. Otros requisitos importantes a tener en cuenta eran la fiabilidad del código y la facilidad de desarrollo desarrollo.. James Gosling, el miembro del equipo con más experiencia en lenguajes de programación, programación, decidió que las ventajas aportadas por la eficiencia de C++ no compensaban el gran coste de pruebas y depuración. Gosling había estado trabajando en su tiempo libre en un lenguaje de programación que él había llamado Oak, el cual, aún partiendo de la sintaxis de C++, intentaba remediar las deficiencias que iba observando. Los lenguajes al uso, como C o C++, deben ser compilados para un chip, y si se cambia el chip, todo el software debe compilarse de nuevo. Esto encarece mucho los desarrollos y el problema es especialmente acusado en el campo de la electrónica de consumo consumo.. La aparición de un chip más barato y, generalmente, más eficiente, conduce inmediatamente a los fabricantes a incluirlo en las nuevas series de sus cadenas de producción producción,, por pequeña que sea la diferencia en precio ya que,
multiplicada por la tirada masiva de los aparatos, supone un ahorro considerable. Por tanto, Gosling decidió mejorar las caracter características ísticas de Oak y utilizarlo. El primer proyecto en que se aplicó este lenguaje recibió el nombre de proyecto Green y consistía en un sistema de control completo de los aparatos electrónicos y el entorno de un hogar. Para ello se construyó construyó un ordenador experimental denominado *7 (Star Seven). El sistema presentaba una interfaz basada en la representación de la casa de forma animada y el control se llevaba a cabo mediante una pantalla sensible al tacto. En el sistema aparecía Duke, la actual mascota de Java Java.. Posteriormente se aplicó a otro proyecto denominado VOD ( Video On Demand) en el que se empleaba como interfaz para la televisión interactiva. Ninguno de estos proyectos se convirtió nunca en un sistema comercial, pero fueron desarrollados enteramente en un Java primitivo y fueron como su bautismo de fuego. Una vez que en Sun se dieron cuenta de que a corto plazo la televisión interactiva no iba a ser un gran éxito, urgieron a FirstPerson a desarrollar con rapidez nuevas estrategias que produjeran beneficios. No lo consiguieron y FirstPerson cerró en la primavera de 1994. Pese a lo que parecía ya un olvido definitivo, Bill Joy, cofundador de Sun y uno de los desarrolladores principales del Unix de Berkeley, juzgó que Internet podría llegar a ser el campo de juego de juego adecuado para disputar a Microsoft su primacía casi absoluta en el terreno del software software,, y vio en Oak el instrumento idóneo para llevar a cabo estos planes. Tras un cambio de nombre y modificaciones de diseño diseño,, el lenguaje Java fue presentado en sociedad en agosto de 1995. Lo mejor será hacer caso omiso de las historias que pretenden dar carta de naturaleza a la clarividencia industrial de sus protagonistas; porque la cuestión es si independientemente de su origen y entorno comercial, Java ofrece soluciones a nuestras expectativas. Porque tampoco vamos a desechar la penicilina aunque haya sido su origen fruto de la casualidad.
1.2 Caracter Características ísticas de Java Las caracter características ísticas principales que nos ofrece Java respecto a cualquier otro lenguaje de programación, programación, son: Simple Java ofrece toda la funcionalidad de un lenguaje potente, pero sin las características caracter ísticas menos usadas y más confusas de éstos. C++ es un lenguaje que adolece de falta de seguridad seguridad,, pero C y C++ son lenguajes más difundidos, por ello Java se diseñó para ser parecido a C++ y así facilitar un rápido y fácil aprendizaje.. aprendizaje Java elimina muchas de las caracter características ísticas de otros lenguajes como C++, para mantener reducidas las especificaciones del lenguaje y añadir características muy útiles como el garbage collector (reciclador de memoria dinámica dinámica). ). No es necesario preocuparse de liberar memoria memoria,, el reciclador se encarga de ello y
como es un thread de baja prioridad, cuando entra en acción, permite liberar bloques de memoria muy grandes, lo que reduce la fragmentación de la memoria.. memoria Java reduce en un 50% los errores más comunes de programación con lenguajes como C y C++ al eliminar muchas de las características de éstos, entre las que destacan: aritmética de punteros no existen referencias registros (struct) definición de tipos (typedef) macros (#define) necesidad de liberar memoria (free) Aunque, en realidad, lo que hace hace es eliminar las palabras reservadas (struct, typedef), ya que las clases son algo parecido. Además, el intérprete completo de Java que hay en este momento es muy pequeño, solamente ocupa 215 Kb de RAM RAM.. Orientado a objetos Java implementa la tecnología básica de C++ con algunas mejoras y elimina algunas cosas para mantener el objetivo de la simplicidad del lenguaje. Java trabaja con sus datos como objetos y con interfaces a esos objetos. Soporta las tres características propias del paradigma de la orientación a objetos: encapsulación, herencia y polimorfismo. Las plantillas de objetos son llamadas, como en C++, clases y sus copias, instancias. Estas instancias, como en C++, necesitan ser construidas y destruidas en espacios de memoria memoria.. Java incorpora funcionalidades inexistentes en C++ como por ejemplo, la resolución dinámica de métodos métodos.. Esta característica deriva del lenguaje Objective C, propietario del sistema operativo Next. En C++ se suele trabajar con librerías dinámicas (DLLs) que obligan a recompilar la aplicación cuando se retocan las funciones que se encuentran en su interior. Este inconveniente es resuelto por Java mediante una interfaz específica llamada RTTI (RunTime Type Identification) que define la interacción entre objetos excluyendo excluyendo variables variables de instancias o implementación de métodos métodos.. Las clases en Java tienen una representación en el runtime que permite a los programadores interrogar por el tipo de clase y enlazar dinámicamente la clase con el resultado de la búsqueda. Distribuido Java se ha construido con extensas capacidades de interconexión TCP/IP TCP/IP.. Existen librerías de rutinas para acceder e interactuar con protocolos como http y ftp y ftp.. Esto permite a los programadores acceder a la información a través de la red con tanta facilidad como a los ficheros locales. La verdad es que Java en sí no es distribuido, sino que proporciona las librerías y herramientas y herramientas para que los programas puedan ser distribuidos, es decir, que se corran en varias máquinas, m áquinas, interactuando. Robusto
Java realiza verificaciones en busca de problemas tanto en tiempo de compilación como en tiempo de ejecución. La comprobación de tipos en Java ayuda a detectar errores, lo antes posible, en el ciclo de desarrollo desarrollo.. Java obliga a la declaración explícita de métodos métodos,, reduciendo así las posibilidades de error. Maneja la memoria para eliminar las preocupaciones por parte del programador de la liberación o corrupción de memoria. También implementa los arrays auténticos, en vez de listas enlazadas de punteros, con comprobación de límites, para evitar la posibilidad de sobreescribir o corromper memoria resultado de punteros que señalan a zonas equivocadas. Estas características reducen drásticamente el tiempo de desarrollo de aplicaciones en Java. Además, para asegurar el funcionamiento de la aplicación, aplicación, realiza una verificación de los byte-codes, que son el resultado resultado de la compilación de un programa Java. Es un código de máquina virtual que es interpretado por el intérprete Java. No es el código máquina directamente entendible por el hardware,, pero ya ha pasado todas las fases del compilador: análisis de hardware instrucciones, orden de operadores, etc., y ya tiene generada la pila de ejecución de órdenes.
Java proporciona, pues: Comprobación de punteros Comprobación de límites de arrays Excepciones Verificación de byte-codes Arquitectura neutral Para establecer Java como parte integral de la red red,, el compilador Java compila su código a un fichero objeto de formato independiente de la arquitectura de la máquina en que se ejecutará. Cualquier máquina que tenga el sistema de ejecución (run-time) puede ejecutar ese código objeto, sin importar en modo alguno la máquina en que ha sido generado. Actualmente existen sistemas runtime para Solaris 2.x, SunOs 4.1.x, Windows 4.1.x, Windows 95, 95, Windows NT, NT, Linux Linux,, Irix, Aix, Mac, Apple y probablemente haya grupos de desarrollo trabajando en el porting a otras plataformas.
El código fuente Java se "compila" a un código de bytes de alto nivel independiente de la máquina. Este código (byte-codes) está diseñado para ejecutarse en una máquina hipotética que es implementada por un sistema runtime, que sí es dependiente dep endiente de la máquina. En una representación en que tuviésemos que indicar todos los elementos que forman parte de la arquitectura de Java sobre una plataforma genérica, obtendríamos una figura como la siguiente:
En ella podemos ver que lo verdaderamente dependiente del sistema es la Máquina Virtual Java (JVM) y las librerías fundamentales, que también nos permitirían acceder directamente al hardware de la máquina. Además, habrá
APIs de Java que también entren en en contacto directo con el hardware hardware y y serán dependientes de la máquina, como ejemplo de este tipo de APIs podemos citar: Java 2D: gráficos 2D y manipulación de imágenes Java Media Framework : Elementos críticos en el tiempo: audio, video audio, video... ... Java Animation: Animación de objetos en 2D Java Telephony: Integración con telefonía Java Share: Interacción entre aplicaciones multiusuario Java 3D: Gráficos 3D y su manipulación Seguro La seguridad en Java tiene dos facetas. En el lenguaje, lenguaje, características como los punteros o el casting implícito que hacen los compiladores de C y C++ se eliminan para prevenir el acceso ilegal a la memoria. memoria. Cuando se usa Java para crear un navegador, se combinan las características del lenguaje con protecciones de sentido común aplicadas al propio navegador. El lenguaje C, C, por ejemplo, tiene lagunas de seguridad importantes, como son los errores de alineación. Los programadores de C utilizan punteros en conjunción con operaciones aritméticas. Esto le permite al programador que un puntero referencie a un lugar conocido de la memoria y pueda sumar (o restar) algún valor algún valor,, para referirse a otro lugar de la memoria. memoria. Si otros programadores conocen nuestras estructuras de datos pueden extraer información confidencial de nuestro sistema. Con un lenguaje como C, se pueden tomar números enteros aleatorios y convertirlos en punteros para luego acceder a la memoria: printf( "Escribe un valor un valor entero: " ); scanf( "%u",&puntero ); printf( "Cadena de memoria: %s\n",puntero ); Otra laguna de seguridad u otro tipo de ataque, es el Caballo de Troya. Se presenta un programa como una utilidad utilidad,, resultando tener una funcionalidad destructiva. Por ejemplo, en UNIX se visualiza el contenido de un directorio con el comando ls. Si un programador deja un comando destructivo bajo esta referencia, se puede correr el riesgo de ejecutar código malicioso, aunque el comando siga haciendo la funcionalidad que se le supone, después de lanzar su carga destructiva. Por ejemplo, después de que el caballo de Troya haya enviado por correo el /etc/shadow a su creador, ejecuta la funcionalidad de ls persentando el contenido del directorio. Se notará un retardo, pero nada inusual. El código Java pasa muchos tests antes de ejecutarse en una máquina. El código se pasa a través de un verificador de byte-codes que comprueba el formato de los fragmentos de código y aplica un probador de teoremas para detectar fragmentos de código ilegal -código que falsea punteros, viola derechos de acceso sobre objetos o intenta cambiar el tipo o clase de un objeto-. Si los byte-codes pasan la verificación sin generar ningún mensaje de error, entonces sabemos que:
• •
•
•
•
El código no produce desbordamiento de operandos en la pila El tipo de los parámetros de todos los códigos de operación son conocidos y correctos. No ha ocurrido ninguna conversión ilegal de datos datos,, tal como convertir enteros en punteros. El acceso a los campos de un objeto se sabe que es legal: public, private, protected. No hay ningún intento de violar las reglas de acceso y seguridad y seguridad establecidas
El Cargador de Clases también ayuda a Java a mantener su seguridad, separando el espacio de nombres del sistema de ficheros local, del de los recursos procedentes de la red red.. Esto limita cualquier aplicación del tipo Caballo de Troya, ya que las clases se buscan primero entre las locales y luego entre las procedentes del exterior. Las clases importadas de la red se almacenan en un espacio de nombres privado, asociado con el origen. Cuando una clase del espacio de nombres privado accede a otra clase, primero se busca en las clases predefinidas (del sistema local) y luego en el espacio de nombres de la clase que hace la referencia. Esto imposibilita que una clase suplante a una predefinida. En resumen, las aplicaciones de Java resultan extremadamente seguras, ya que no acceden a zonas delicadas de memoria o de sistema, con lo cual evitan la interacción de ciertos virus ciertos virus.. Java no posee una semántica específica para modificar la pila de programa programa,, la memoria libre o utilizar objetos y métodos y métodos de un programa sin los privilegios del kernel del sistema operativo. operativo. Además, para evitar modificaciones por parte de los crackers de la red, implementa un método ultraseguro de autentificación por clave pública. El Cargador de Clases puede verificar una firma digital antes antes de realizar una instancia de un objeto. objeto. Por tanto, ningún objeto se crea y almacena en memoria, sin que se validen los privilegios de acceso. Es decir, la seguridad se integra en el momento de compilación, con el nivel de detalle y de privilegio que sea necesario. Dada, pues la concepción del lenguaje y si todos los elementos se mantienen dentro del estándar marcado por Sun, no hay peligro. Java imposibilita, también, abrir ningún fichero de la máquina local (siempre que se realizan operaciones con archivos archivos,, éstas trabajan sobre el disco duro de la máquina de donde partió el applet), no permite ejecutar ninguna aplicación nativa de una plataforma e impide que se utilicen otros ordenadores como puente, es decir, nadie puede utilizar nuestra máquina para hacer peticiones o realizar operaciones con otra. Además, los intérpretes que incorporan los navegadores de la Web la Web son aún más restrictivos. Bajo estas condiciones (y dentro de la filosofía de que el único ordenador seguro es el que está apagado, desenchufado, dentro de una cámara acorazada en un bunker y rodeado por mil soldados de los cuerpos especiales del ejército), se puede considerar que Java es un lenguaje seguro y que los applets están libres de virus de virus.. Respecto a la seguridad del código fuente, no ya del lenguaje, JDK proporciona un desemsamblador de byte-code, que permite que cualquier programa pueda ser convertido a
código fuente, lo que para el programador significa una vulnerabilidad total a su código. Utilizando javap no se obtiene el código fuente original, pero sí desmonta el programa mostrando el algoritmo que se utiliza, que es lo realmente interesante. La protección de los programadores ante esto es utilizar llamadas a programas nativos, externos (incluso en C o C++) de forma que no sea descompilable todo el código; aunque así se pierda portabilidad. Esta es otra de las cuestiones que Java tiene pendientes. Portable Más allá de la portabilidad básica por ser de arquitectura independiente, Java implementa otros estándares de portabilidad para facilitar el desarrollo. Los enteros son siempre enteros y además, enteros de 32 bits en complemento a 2. Además, Java construye sus interfaces de usuario usuario a través de un sistema abstracto de ventanas de forma que las ventanas puedan ser implantadas en entornos Unix Unix,, Pc o Mac. Interpretado El intérprete Java (sistema run-time) puede ejecutar directamente el código objeto. Enlazar (linkar) un programa, normalmente, consume menos recursos que compilarlo, por lo que los desarrolladores con Java pasarán más tiempo desarrollando y menos esperando por el ordenador. No obstante, el compilador actual del JDK es bastante lento. Por ahora, que todavía no hay compiladores hay compiladores específicos de Java para las diversas plataformas, Java es más lento que otros lenguajes de programación, programación, como C++, ya que debe ser interpretado y no ejecutado como sucede en cualquier c ualquier programa tradicional. Se dice que Java es de 10 a 30 veces más lento que C, y que tampoco existen en Java proyectos de gran envergadura como en otros lenguajes. La verdad es que ya hay comparaciones ventajosas entre Java y el resto de los lenguajes de programación,, y una ingente cantidad de folletos electrónicos que supuran programación fanatismo en favor y en contra de los distintos lenguajes contendientes con Java. Lo que se suele dejar de lado en todo esto, es que primero habría que decidir hasta que punto Java, un lenguaje en pleno desarrollo y todavía sin definición definitiva, está maduro como lenguaje de programación para ser comparado con otros; como por ejemplo con Smalltalk, que lleva más de 20 años en cancha. La verdad es que Java para conseguir ser un lenguaje independiente del sistema operativo y del procesador que incorpore la máquina utilizada, es tanto interpretado como compilado. Y esto es to no es ningún contrasentido, me explico, el código fuente escrito con cualquier editor se compila generando el byte-code. Este código intermedio es de muy bajo nivel, pero sin alcanzar las instrucciones máquina propias de cada plataforma y no tiene nada que ver con el p-code de Visual de Visual Basic. Basic. El byte-code corresponde al 80% de las instrucciones de la aplicación. Ese mismo código es el que se puede ejecutar sobre cualquier plataforma. Para ello hace falta el runtime, que sí es completamente dependiente de la máquina y del sistema operativo,, que interpreta dinámicamente el byte-code y añade el 20% de operativo instrucciones que faltaban para su ejecución. Con este sistema es fácil crear aplicaciones multiplataforma, pero para ejecutarlas es necesario que exista el run-time correspondiente al sistema operativo utilizado.
Multithreaded Al ser multithreaded (multihilvanado, en mala traducción), Java permite muchas actividades simultáneas en un programa. Los threads (a veces llamados, procesos ligeros), son básicamente pequeños procesos o piezas independientes de un gran proceso proceso.. Al estar los threads contruidos en el lenguaje, lenguaje, son más fáciles de usar y más robustos que sus homólogos en C o C++. El beneficio de ser miltithreaded consiste en un mejor rendimiento interactivo y mejor comportamiento en tiempo real. Aunque el comportamiento en tiempo real está limitado a las capacidades del sistema operativo subyacente (Unix (Unix,, Windows,, etc.), aún supera a los entornos de flujo único de programa (single Windows threaded) tanto en facilidad de desarrollo como en rendimiento. Cualquiera que haya utilizado la tecnología de navegación concurrente, sabe lo frustrante que puede ser esperar por una gran imagen que se está trayendo. En Java, las imágenes se pueden ir trayendo en un thread independiente, permitiendo que el usuario pueda acceder a la información en la página sin tener que esperar por el navegador. Dinamico Java se beneficia todo lo posible de la tecnología orientada a objetos. Java no intenta conectar todos los módulos que comprenden una aplicación hasta el tiempo de ejecución. Las librería nuevas o actualizadas no paralizarán las aplicaciones actuales (siempre que mantengan el API anterior).
Java también simplifica el uso de protocolos nuevos o actualizados. Si su sistema ejecuta una aplicación Java sobre la red y encuentra una pieza de la aplicación que no sabe manejar, tal como se ha explicado en párrafos anteriores, Java es capaz de traer automáticamente cualquiera de esas piezas que el sistema necesita para funcionar.
Java, para evitar que los módulos de byte-codes o los objetos o nuevas clases, haya que estar trayéndolos de la red cada vez que se necesiten, implementa las opciones de persistencia, para que no se eliminen cuando de limpie la caché de la máquina. ¿Cuál es la ventaja de todo esto?¿Qué gano con Java? •
•
•
•
•
Primero: No debes volver a escribir el código si quieres ejecutar el programa en otra máquina. Un solo código funciona para todos los browsers compatibles con Java o donde se tenga una Máquina Virtual de Java (Mac's, PC's, Sun's, etc). Segundo: Java es un lenguaje de programación orientado a objetos, y tiene todos los beneficios que ofrece esta metodología de programacion (más adelante doy una pequeña introducción a la filosofía de objetos). Tercero: Un browser compatible con Java deberá ejecutar cualquier programa hecho en Java, esto ahorra a los usuarios tener que estar insertando "plug-ins" y demás programas que a veces nos quitan tiempo y espacio en disco. Cuarto: Java es un lenguaje y por lo tanto puede hacer todas las cosas que puede hacer un lenguaje de programación: programación: Cálculos matemáticos, procesadores de palabras, bases palabras, bases de datos, datos, aplicaciones gráficas, animaciones, sonido,, hojas de cálculo sonido cálculo,, etc. Quinto: Si lo que me interesa son las páginas de Web de Web,, ya no tienen que ser estáticas, se le pueden poner toda clase de elementos multimedia multimedia y y permiten un alto nivel de interactividad, sin tener que gastar en paquetes p aquetes carísimos de multimedia multimedia..
Todo esto suena muy bonito pero tambien se tienen algunas limitantes: • •
•
La velocidad.. La velocidad Los programas hechos en Java no tienden a ser muy rápidos, supuestamente se está trabajando en mejorar esto.Como los programas de Java son interpretados nunca alcanzan la velocidad la velocidad de un verdadero ejecutable. Java es un lenguaje de programación programación.. Esta es otra gran limitante, por más que digan que es orientado a objetos y que es muy fácil de aprender sigue siendo un lenguaje y por lo tanto aprenderlo no es cosa fácil. Especialmente para los no programadores.
•
Java es nuevo. En pocas palabras todavía no se conocen bien todas sus capacidades.
Pero en general Java posee muchas ventajas y se pueden hacer cosas muy interesantes con esto. Hay que prestar especial atención a lo que está sucediendo en el mundo de la computación computación,, a pesar de que Java es relativamente nuevo, posee mucha fuerza fuerza y y es tema de moda en cualquier medio computacional. Muchas personas apuestan a futuro y piensan en Java. La pregunta es : ¿Estarán en lo correcto? La verdad es que no se, pero este manual no es para filosofar sobre el futuro del lenguaje sino para aprender a programarlo.
1.3 HotJava HotJava, en pocas palabras, es un navegador con soporte Java (Java-enabled), desarrollado en Java. Como cualquier navegador de Web de Web,, HotJava puede decodificar HTML estándar y URLs estándares, aunque no soporta completamente el estándar HTML 3.0. La ventaja sobre el resto de navegadores navegadores,, sin soporte Java, es que puede ejecutar programas Java sobre la red. La diferencia con Netscape, es que tiene implementado completamente los sistemas de seguridad que propone Java, esto significa que puede escribir y leer en el disco local, aunque esto hace disminuir la seguridad, ya que se pueden grabar en nuestro disco programas que contengan código malicioso e introducirnos un virus un virus,, por ejemplo. No obstante, el utilizar esta característica de HotJava es decisión del usuario.
1.4 Java para aplicaciones corporativas Java actualmente está en boca de todos, Java e Intranet son las palabras de moda.. Pero, surge la pregunta de si esta es una buena tecnología para moda desarrollar aplicaciones corporativas. Y la respuesta es afirmativa y voy a proponer argumentos para esa afirmación. En donde la red sea algo crítico, Java facilita tremendamente la vida de la programación corporativa. Durante años, las grandes empresas se han convencido de que la "red" corporativa es la arteria por donde fluye la sangre que mantiene vivo su negocio. Desde el gran servidor de sus oficinas centrales, hasta los servidores de las delegaciones, las estaciones de trabajo de los programadores y la marabunta de PCs, la información va fluyendo de unos a otros. Para muchas compañías, la Red es la Empresa. Empresa. Si esta red no se mantiene sana, los pedidos no llegan, el inventario no se actualiza, el software no se desarrolla adecuadamente, los clientes no están satisfechos y, fundamentalmente, el dinero no entra. La necesidad de diagnosticar y reducir la arterioesclerosis de la red, hace que se estén inyectando continuamente nuevas metodologías que subsanen este grave problema. ¿Es Java la medicina medicina?? Está claro que cuando vemos un cepillo animado limpiando los dientes, cubos moviéndose en 3-D, o una banda de gatos locos en applets de Java, nos convencemos de que es el lenguaje idóneo para Internet Internet.. Pero, qué pasa con las aplicaciones corporativas, ¿sería una buena tecnología allí donde la red es el punto crítico? Vamos a intentar responder comparando las capacidades de Java contra la lista de necesidades de la red corporativa. Desarrollo rápido de aplicaciones
Hace años, se decía que los programadores pronto desaparecerían. Los generadores automáticos de programas, eliminarían a los generadores humanos y el mundo sería un lugar mejor para vivir. Desafortunadamente, Desafortunadamente, quienes decían esto no tuvieron en cuenta una acelerada demanda de software de calidad para muy diferentes aplicaciones. Sin embargo, la tecnología de objetos pronto vino a intentar facilitar la tarea, adoptando el modelo de "generar parte de un programa", así, generando la parte básica de un programa (los objetos), se podría conectar con otras partes para proporcionar diferentes utilidades al usuario. El lenguaje C++ C++ es una buena herramienta, pero no cumple totalmente la premisa. Visual premisa. Visual Basic y NextStep, se acercan cada vez más al poder de los objetos. Java facilita la creación de entornos de desarrollo-aplicaciones de modo similar, pero además es flexible, poderoso y efectivo. Los programadores ahora disponen de herramientas de programación de calidad calidad beta, beta, que apuntan hacia hacia esa meta, como son el Java WorkShop de SunSoft, el entorno Java de Borland, el Café de Symantec, y pronto, herramientas más sofisticadas como Netcode o FutureTense. Esto proporciona una gran progresión a los entornos de desarrollo Java. Aplicaciones efectivas y eficientes Las aplicaciones que se crean en grandes empresas deben ser más efectivas que eficientes; es decir, conseguir que el programa funcione y el y el trabajo salga adelante es más importante que el que lo haga eficientemente. Esto no es una crítica, es una realidad de la programación corporativa. Al ser un lenguaje más simple que cualquiera de los que ahora están en el cajón de los programadores, Java permite a éstos concentrarse en la mecánica de la aplicación, en vez de pasarse horas y horas incorporando APIs para el control de las ventanas, controlando minuciosamente la memoria, sincronizando los ficheros de cabecera y corrigiendo los agónicos mensajes del linker. Java tiene su propio toolkit para interfaces, maneja por sí mismo la memoria que utilice la aplicación, no permite ficheros de cabecera separados (en aplicaciones puramente Java) y solamente usa enlace dinámico. Muchas de las implementaciones de Java actuales son puros intérpretes. Los byte-codes son interpretados por el sistema run-time run-time de Java, la Máquina Virtual Java (JVM), sobre el ordenador del usuario. usuario. Aunque ya hay ciertos proveedores que ofrecen compiladores nativos Just-In-Time (JIT). Si la Máquina Virtual Java dispone de un compilador instalado, las secciones (clases) del byte-code de la aplicación se compilarán hacia la arquitectura nativa del ordenador del usuario. Los programas Java en ese momento rivalizarán con el rendimiento de programas en C++. Los compiladores JIT no se utilizan en la forma tradicional de un compilador; los programadores no compilan y distribuyen binarios Java a los usuarios. La compilación JIT tiene lugar a partir del byte-code Java, en el sistema del usuario, como una parte (opcional) del entorno run-time local de Java. Muchas veces, los programadores corporativos, ansiosos por exprimir al máximo la eficiencia de su aplicación, empiezan a hacerlo demasiado pronto en el ciclo de vida de la aplicación. Java
permite algunas técnicas innovadoras de optimización. Por ejemplo, Java es inherentemente multithreaded, a la vez que ofrece posibilidades de multithread como la clase Thread y mecanismos muy sencillos de usar de sincronización; Java en sí utiliza threads. Los desarrolladores de compiladores inteligentes pueden utilizar esta característica de Java para lanzar un thread que compruebe la forma en que se s e está utilizando la aplicación. Más específicamente, este thread podría detectar qué métodos de una clase se están usando con más frecuencia e invocar a sucesivos niveles de optimización en tiempo de ejecución de la aplicación. Cuanto más tiempo esté corriendo la aplicación o el applet, los métodos estarán cada vez más optimizados (Guava de Softway es de este tipo). Si un compilador JIT está embebido en el entorno run-time de Java, el programador no se preocupa de hacer que la aplicación se ejecute óptimamente. Siempre he pensado que en los Sistemas Operativos tendría que aplicarse esta filosofía; un optimizador progresivo es un paso más hacia esta idea. Portabilidad para programador y programa En una empresa de relativo tamaño hay una pléyade diferente de ordenadores. Probablemente nos encontremos con estaciones de trabajo Sun para el desarrollo de software, hordas de PCs para cada empleado, algún Mac en el departamento de documentación, una estación de trabajo HP en administración y una estación SGI en la sala de demos. Desarrollar Desarrollar aplicaciones corporativas para un grupo tan diferente de plataformas en excesivamente complejo y caro. Hasta ahora era complicado convencer a los programadores de cada arquitectura que utilizasen un API común para reducir el coste de las aplicaciones. Con un entorno run-time de Java portado a cada una de las arquitecturas de las plataformas presentes en la empresa y una buena librería de clases ("packages" en Java), los programadores pueden entenderse y encontrar muy interesante trabajar con Java. Esta posibilidad hará tender a los programadores hacia Java, justo donde otros intentos anteriores anteriores con entornos universales (como Galaxy o XVT) han fracasado. Estos APIs eran simplemente inadecuados, no orientados a redes y, verdaderamente, pesados. Una vez que los programas estén escritos en Java, otro lado interesante del asunto es que los programadores también son portables. El grupo de programadores de la empresa puede ahora enfrentarse a un desarrollo para cualquiera de las plataformas. La parte del cliente y del servidor de una aplicación estarán ahora escritas en el mismo lenguaje. Ya no será necesario tener un grupo que desarrolle en Solaris en del departamento de I+D, programadores trabajando sobre Visual sobre Visual Basic en el departamento de documentación y programadores sobre GNU en proyectos especiales; ahora todos ellos podrán estar juntos y formar el grupo de software de la empresa. empresa. Costes de desarrollo En contraste con el alto coste de los desarrollos realizados sobre estaciones de trabajo, el coste de creación de una aplicación Java es similar al de desarrollar sobre un PC. Desarrollar utilizando un software caro para una estación de trabajo (ahora barata) es un problema en muchas empresas empresas.. La eficiencia del hardware hardware y y
el poco coste de mantenimiento de una estación de trabajo Sun, por ejemplo, resulta muy atractivo para las empresas empresas;; pero el coste adicional del entorno de desarrollo con C++ es prohibitivo para la gran mayoría de ellas. La llegada de Java e Intranet reducen considerablemente estos costes. Las herramientas Java ya no están en el entorno de precios de millones de pesetas, sino a los niveles confortables de precio de las herramientas de PCs. Y con el crecimiento cada día mayor de la comunidad de desarrolladores de software freeware y shareware que incluso proporcionan el código fuente, los programadores corporativos tienen un amplio campo donde moverse y muchas oportunidades de aprender y muchos recursos a su disposición. El éxito que Internet ha proporcionado a los equipos de software corporativos es un regalo. El precio del software es ahora el mismo para un poderoso equipo corriendo Unix que para un PC. Incluso Netscape tiene al mismo precio la versión Unix de su servidor servidor Web Web SuiteSpot que la versión PC/NT. Esta es la filosofía de precios que parece ser será la que se siga con las herramientas basadas en Java. Mantenimiento y soporte Un problema bien conocido que ocurre con el software corporativo es la demanda de cuidados y realimentación. Java no es, ciertamente, ciertamente, la cura para la enfermedad del mantenimiento mantenimiento,, pero tiene varias características que harán la vida del enfermero más fácil. Uno de los componentes del JDK es javadoc. Si se usan ciertas convenciones en el código fuente Java (como comenzar un comentario con /** y terminarlo con */), javadoc se puede fácilmente generar páginas HTML con el contenido de esos comentarios, que pueden visualizarse en cualquier navegador. La documentación del API de Java ha sido creada de este modo. Esto hace que el trabajo de documentar el código de nuevas clases Java sea trivial. Otro gran problema del desarrollador corporativo es la creación y control y control de makefiles. Leerse un makefile es como estar leyendo la historia de empresa empresa.. Normalmente se pasan de programador a programador, quitando la información que no es esencial, siempre que se puede. Esto hace que muchos de los makefiles de las aplicaciones contengan docenas de librerías, una miríada de ficheros de cabecera y ultra-confusos macros macros.. Es como mirar en el estómago de la ballena de Jonás. Java reduce las dependencia de complejos makefiles drásticamente. Primero, no hay ficheros de cabecera. Java necesita que todo el código fuente de una clase se encuentre en un solo fichero. Java tiene la inteligencia de make en el propio lenguaje para simplificar la compilación de byte-codes. Por ejemplo: public class pepe { // Fichero: pepe.java Guitarra flamenca ; }
public class guitarra { // Fichero: guitarra.java } % javac -verbose pepe.java [parsed pepe.java in 720ms] [loaded C:\JAVA\BIN\..\classes\java\lang\Object.class C:\JAVA\BIN\..\classes\java\lang\Object.class in 220ms] [checking class pepe] [parsed .\\Guitarra.java in 50ms] [wrote pepe.class] [checking class Guitarra] [wrote .\\Guitarra.class] [done in 2300ms] El compilador Java se da cuenta de que necesita compilar el fichero guitarra.java. Ahora vamos a forzarlo a que recompile pepe.java sin cambiar guitarra.java, podremos comprobar que el compilador de byte-code Java no recompila innecesariamente el fichero guitarra.java. % javac -verbose pepe.java [parsed pepe.java in 440ms] [loaded C:\JAVA\BIN\..\classes\java\lang\Object.class C:\JAVA\BIN\..\classes\java\lang\Object.class in 160ms] [checking class pepe] [loaded .\\Guitarra.java in 0ms] [wrote pepe.class] [done in 1860ms] Ahora, si modificamos guitarra.java (añadiendo, (añadiendo, por ejemplo, otro miembro a la clase) y compilamos pepe.java, el compilador Java se dará cuenta de que debe recompilar tanto pepe.java como guitarra.java % javac -verbose pepe.java [parsed pepe.java in 710ms] [loaded C:\JAVA\BIN\..\classes\java\lang\Object.class C:\JAVA\BIN\..\classes\java\lang\Object.class in 220ms] [checking class pepe] [parsed .\\Guitarra.java in 0ms] [wrote pepe.class] [checking class Guitarra] [wrote .\\Guitarra.class] [done in 2640ms] En el libro Just Java de Peter van der Linden hay un capítulo excelente acerca del compilador de Java, si tienes oportunidad, no dejes de leerlo.
Aprendizaje Si la empresa está llena de programadores de C++ con alguna experiencia en el manejo de librería gráficas, aprenderán rápidamente lo esencial de Java. Si el equipo de ingenieros no conoce C++, pero maneja cualquier otro lenguaje de programación orientada a objetos, objetos, les llevará pocas semanas dominar la base de Java. Lo que sí que no es cierto es que haya que aprender C++ antes de aprender Java. Si los ingenieros de la empresa no conocen ningún lenguaje orientado a objetos, sí que tienen que aprender los fundamentos de esta tecnología antes de nada, y luego aplicarlos a la programación con Java. El análisis y y diseño diseño orientado a objetos debe ser comprendido antes de intentar nada con Java. Los programadores de Java sin un fondo de conocimientos de OOA/D producirán código pobre. Además, los libros sobre Java crecen como la espuma, ya hay más de 25 publicados, y si buscas "Progamming in Java" en la Red, encontrarás 312 Web sites, y 30 más dedicados a "Learning Java". Y si esto, evidentemente, no es el sustituto de un instructor humano, hay ya varias empresas que ofrecen enseñanza de Java, entre ellas, Sun.
2. INSTALACIÓN DEL JDK Actualmente ya hay entornos de desarrollo integrados integrados completos para Java, diferentes del JDK de Sun. Symantec dispone de un compilador de Java para Windows para Windows 95 y 95 y Windows Windows NT, NT, con las ventajas del aumento de velocidad de velocidad de proceso y capacidades multimedia que esto proporciona, Symantec Café. Borland también está trabajando en ello y la nueva versión de su entorno de desarrollo soporta Java. Sun ha lanzado la versión comercial de su propio entorno de desarrollo para Java, el Java Workshop, enteramente escrito en Java. Y Microsoft Y Microsoft ha puesto en el mercado Visual J++, que sigue el estilo estilo de todas sus herramientas de desarrollo. No obstante, trataremos solamente el JDK, que hasta el momento es lo más conocido. El entorno básico del JDK de Java que proporciona Sun está formado por herramientas en modo texto texto,, que son: java, intérprete que ejecuta programas en byte-code. javac, compilador de Java que convierte el código fuente en byte-code. javah, crea ficheros de cabecera para implementar métodos para cualquier clase. javap, es un descompilador de byte-code a código fuente Java. javadoc, es un generador automático de documentos HTML a partir del código fuente Java. javaprof, es un profiler para aplicaciones de un solo thread. HotJava, es un navegador Web escrito completamente en Java. El entorno habitual pues, consiste en un navegador que pueda ejecutar applets, un compilador que convierta el código fuente Java a byte-code y el intérprete Java para ejecutar los programas. Estos son los componenetes básicos para desarrollar algo en Java. No obstante se necesita un editor para escribir el código fuente, y no son estrictamente necesarias otras herramientas como el debugger, un entorno visual, la documentación o un visualizador de jerarquía de clases. Tan es así, que disponiendo del navegador Netscape 2.0 no se necesita ni
tan siquiera el JDK (a petición de varios amigos que disfrutan del uso de Linux pero no disponen de soporte ELF para poder utilizar el JDK portado por Randy Chapman, les indicaré como conseguir utilizar el compilador embebido en Netscape).
2.1 Windows 2.1 Windows La versión del JDK para Windows para Windows es un archivo autoextraible. Se necesitan alrededor de 6 Mb de espacio libre en disco. Ejecutar el fichero, que desempaquetará el contenido del archivo archivo.. El directorio donde se instale no es importante, pero supondremos que se instala en el raiz del disco C:, en cuyo caso los archivos colgarán de c:\java. Es necesario añadir c:\java\bin a la variable de entorno PATH. Además de los ficheros java, el JDK incluye dos librerías dinámicas, MSVCRT20.DLL y MFC30.DLL, que se instalarán en el directorio de Java. Si tienes ninguna copia de estos ficheros en tu ordenador (probablemente en el directorio system de Windows de Windows)) copia estos ficheros en el directorio c:\java\bin. Si estos ficheros ya están en tu ordenador, elimina las copias extra que instala el JDK.
2.2 Solaris La versión del JDK para Solaris es un fichero tar comprimido. Se necesitan alrededor de 9 Mb de disco para descomprimir el JDK, aunque el doble de espacio sería una cifra más cómoda cómoda.. Ejecutar los siguientes comandos comandos:: % uncompress JDK-beta-solaris2-sparc.tar.Z % tar xvf JDK-beta-solaris2-sparc-tar Puedes descomprimir el archivo en tu directorio home, o, si tienes privilegios de supervisor, en algún sitio más conveniente de /usr/local para que todos los usuarios tengan acceso a los ficheros. Sin embargo, los privilegios del supervisor no son necesarios para instalar y ejecutar Java. Por simplicidad, supondré que has descomprimido el JDK en /usr/local, aunque el path completo donde se haga no tiene relevancia (también es posible colocarlo en /opt que es donde residen todas las aplicaciones de Solaris). Si lo has colocado en un sitio diferente, simplemente sustituye /usr/local por ese directorio (si (s i lo has descomprimido en tu home, puedes utilizar ~/java y ~/hotjava, en vez del path completo). Es necesario añadir /usr/local/java/bin a la variable de entorno PATH. Utiliza el siguiente comando (suponiendo que tengas el shell csh o tcsh): set path=($PATH /usr/local/java/bin) También puedes añadir esta línea al final del fichero .profile y .cshrc, y ya tienes el sistema listo para ejecutar applets. Si quieres desembarazarte de la ventana que aparece cada vez que lances el appletviewer con la licencia de Sun, crea un directorio que se llame .hotjava en el directorio java/bin y ya no volverás a verla.
2.3 Linux Necesitas un kernel que soporte binarios ELF, por lo tanto tu Linux debe ser la versión 1.2.13 o superior, las anteriores tienen un bug que hacen que javac no funcione. Necesitas también Netscape, versión 2.0b4 o posterior. Sobre la
versión 1.2.13 del kernel de Linux Linux,, hay que seguir los pasos que indico para conseguir que JDK funcione: •
Bajarse el JDK, linux linux.jdk-1.0-try4.sta .jdk-1.0-try4.static-motif.tar.gz tic-motif.tar.gz y
linux.jdk-1.0 try1.common.tar.gz a /usr/local, descomprimirlo y hacer 'tar xvf' •
En el fichero .java_wrapper (si no existe, crearlo) cambiar las variable J_HOME y PRG, para que queden como: c omo:
J_HOME=/usr/local/java PRG=/usr/local/java/bin •
•
•
•
•
•
•
Bajarse la librería libc.5.2.18.bin.tar.gz a /, descomprimirla, hacer 'tar xvf'. Asegurarse de que /lib/libc.so.5 es un link link simbólico a este nuevo fichero.Si no lo es, hacer el /lib 'ln -s libc.so.5.2.18 libc.so.5' Bajarse ld-so.1.7.14.tar.gz a un directorio temporal, descomprimirlo y hacer 'tar xvf'. Ejecutar 'instldso.sh' y eliminar el directorio temporal. Añadir /usr/local/java a la variable de entorno PATH. Si se desea que esté fijada para todos los usuarios, incorporar el directorio a la varible PATH que se fija en el fichero /etc/profile. Bajarse netscape-v202-export.i486-unknown-linux.tar.z a usr/local/netscape, descomprimirlo y hacer 'tar xvf' Crear un link en /usr/local/bin a /usr/local/netscape/netscape
Esto debería ser suficiente para compilar cualquier cosa en Java/Linux. En caso de tener problemas problemas,, es el momento de recurrir a las FAQ. Siguiendo los pasos indicados ya se puede ejecutar el ejemplo del Tic-Tac-Toe que propone la hoja de instalación que Sun ha incluido en todas sus versiones y que en Linux consistiría en cambiarse al directorio de la demo: % cd /usr/local/java/demo/TicTacToe ejecutar el visualizador de applets sobre la página html html:: % appletviewer example1.html y a jugar a las tres en raya. Por cierto, que que el algoritmo que usa el ordenador está falseado por lo que es posible ganarle.
2.4 Compilación sin JDK
Parece raro, pero se puede conseguir. Lo único necesario es el navegador Netscape 2.0. Este navegador, junto con la máquina virtual Java (JVM) y el sistema run-time, tiene un compilador Java. Si no se dispone del Java Development Kit (JDK), que no está disponible para todas las plataformas, pero sí de la versión de Netscape para nuestra plataforma, aquí van los pasos a seguir para utilizar el compilador de Java embebido en Netscape. Como necesito partir de algún punto para tomarlo como referencia, voy a suponer que estamos sobre Linux y que vamos a prescindir del JDK de Randy Chapman. Lo que habría que hacer sería lo siguiente. •
•
•
Primero. Instalar Netscape en el ordenador. Asegurarse de entender perfectamente y leerse hasta el final el fichero README, para seguir las instrucciones específicas de la instalación de Netscape en la plataforma y que Netscape funcione perfectamente. En nuestro caso, en que vamos a intentar compilar código Java con Netscape sobre Linux, la pieza clave es la situación del fichero moz2_0.zip, que en mi máquina m áquina está en /usr/local/netscape/java/classes. Segundo. Extraer de una copia cualquiera del JDK (aunque sea de otra plataforma), el fichero java/lib/classes.zip y guardarlo en el mismo sitio que el fichero moz2_0.zip; esta localización no es necesaria, pero simplifica la estructura.. estructura Tercero. Fijar la variable de entorno CLASSPATH para que Netscape pueda encontrar sus propias clases además de las clases del Java de Sun. Asegurarse de incluir el "directorio actual", actual", para poder compilar a la vez que se usan los ficheros .zip de Netscape y Sun. Por ejemplo:
setenv CLASSPATH .:/usr/local/netscape/java/classes/moz2_0.zip .:/usr/local/netscape/java/ classes/moz2_0.zip : /usr/local/netscape/java/classes/classes.zip •
•
Cuarto. Compilar el código Java (applet o aplicación) con el comando: netscape -java sun.tools.javac.Main [fichero].java (sustituir el nombre del fichero con el código Java en vez de [fichero]). Esto convertirá el código fuente Java en byte-code, generándose el archivo [fichero].class. Quinto. Comprobar si se puede ejecutar la aplicación con el comando:
netscape -java [clase] (sustituir el nombre de la clase de la aplicación -la que contiene la rutina mainen vez de [clase]). •
Sexto. Si se ha compilado un applet Java, construir una página html que lo utilice para visualizarlo con el navegador en su forma normal. O también se puede visualizar utilizando el appletviewer, ejecutando:
netscape -java sun.applet.AppletViewer [clase] Desgraciadamente, la sentencia anterior no parece funcionar en todos los
sistemas. Hay amigos míos que no han sido capaces de visualizar applets con este método método.. Para aprovechar el tiempo, se puede crear un script que recoja los pasos 3, 4 y 6. Si estamos utilizando el csh, el contenido del script sería: #/bin/csh -f setenv CLASSPATH .:/usr/local/netscape/java/classes/moz2_0.zip: /usr/local/netscape/java/classes/classes.zip netscape -java sun.tools.javac.Main $1 y lo almacenaríamos como javac. Se ha de hacer el script ejecutable ejecutable y cambiar /bin/csh por el path completo donde esté situado el csh. De forma semejante podemos definir el intérprete java y el appletviewer, sustituyendo la línea adecuada de llamada a Netscape.
3. CONCEPTOS BÁSICOS DE JAVA 3.1 Programación en Java Cuando se programa en Java, se coloca todo el código en métodos, de la misma forma que se escriben funciones en lenguajes como C. Comentarios En Java hay tres tipos de comentarios: // comentarios para una sola línea /* comentarios de una o más líneas */ /** comentario de documentación, de una o más líneas */ Los dos primeros tipos de comentarios son los que todo programador conoce y se utilizan del mismo modo. Los comentarios de documentación, colocados inmediatamente antes de una declaración (de variable o función), indican que ese comentario ha de ser colocado en la documentación que se genera automáticamente cuando se utiliza la herramienta de Java, javadoc. Dichos comentarios sirven como descripción del elemento declarado permitiendo generar una documentación de nuestras clases escrita al mismo tiempo que se genera el código. En este tipo de comentario para documentación, se permite la introducción de algunos tokens o palabras clave, que harán que la información que les sigue aparezca de forma diferente al resto en la documentación. Identificadores Los identificadores nombran variables nombran variables,, funciones funciones,, clases y objetos; cualquier c ualquier cosa que el programador necesite identificar o usar.
En Java, un identificador comienza con una letra, un subrayado (_) o un símbolo de dólar ($). Los siguientes caracteres pueden ser letras o dígitos. Se distinguen las mayúsculas de las minúsculas y no hay longitud máxima. Serían identificadores válidos: identificador nombre_usuario Nombre_Usuario _variable_del_sistema $transaccion y su uso sería, por ejemplo: int contador_principal; char _lista_de_ficheros; float $cantidad_en_Pt $cantidad_en_Ptas; as; Palabras clave Las siguientes son las palabras clave que están definidas en Java y que no se pueden utilizar como indentificadores: abstract continue for new switch boolean default goto null synchronized synchronized break do if package this byte double implements private threadsafe threadsafe byvalue else import protected throw case extends instanceof public transient catch false int return true char final interface short try class finally long static void const float native super while Palabras Reservadas Además, el lenguaje se reserva unas cuantas cuantas palabras más, pero que hasta ahora no tienen un cometido específico. Son: cast future generic inner operator outer rest var Literales Un valor constante en Java se crea utilizando una representación literal de él. Un valor Java utiliza cinco tipos de elementos: enteros, reales en coma flotante, booleanos, caracteres y cadenas, que se pueden poner en cualquier cualquier lugar del código fuente de Java. Cada uno de estos literales tiene un tipo correspondiente asociado con él.
Enteros: byte 8 bits complemento a dos short 16 bits complemento a dos int 32 bits complemento a dos long 64 bits complemento a dos Por ejemplo: 21 077 0xDC00 Reales en coma flotante: float 32 bits IEEE 754 double 64 bits IEEE 754 Por ejemplo: 3.14 2e12 3.1E12 Booleanos: true false Caracteres: Por ejemplo: a \t \u???? [????] es un número unicode Cadenas: Por ejemplo: "Esto es una cadena literal" Arrays Se pueden declarar en Java arrays de cualquier tipo: char s[]; int iArray[]; Incluso se pueden construir arrays de arrays: int tabla[][] = new int[4][5]; Los límites de los arrays se comprueban en tiempo de ejecución para evitar desbordamientos y la corrupción de memoria. En Java un array es realmente un objeto, porque tiene redefinido el operador []. Tiene una función miembro: length. Se puede utilizar este método para conocer la longitud de cualquier array. int a[][] = new int[10][3]; a.length; /* 10 */ a[0].length; /* 3 */ Para crear un array en Java hay dos métodos básicos. Crear un array vacío: int lista[] = new int[50]; o se puede crear ya el array con sus valores sus valores iniciales:
String nombres[] = { "Juan","Pepe","Pedro","Maria" }; Esto que es equivalente a: String nombres[]; nombres = new String[4]; nombres[0] = new String( "Juan" ); nombres[1] = new String( "Pepe" ); nombres[2] = new String( "Pedro" ); nombres[3] = new String( "Maria" ); No se pueden crear arrays estáticos en tiempo de compilación: int lista[50]; // generará un error en tiempo de compilación Tampoco se puede rellenar un array sin declarar el tamaño con el operador new: int lista[]; for( int i=0; i < 9; i++ ) lista[i] = i; Es decir, todos los arrays en Java son estáticos. Para convertir un array en el equivalente a un array dinámico en C/C++, se usa la clase vector, que permite operaciones de inserción, borrado, etc. en el array. Operadores Los operadores de Java son muy parecidos en estilo y funcionamiento a los de C. En la siguiente tabla aparecen los operadores que se utilizan en Java, por orden de precedencia: . [] () ++ -! ~ instanceof */% +<< >> >>> < > <= >= == != &^| && || ?: = op= (*= /= %= += -= etc.) , Los operadores numéricos se comportan como esperamos:
int + int = int Los operadores relacionales devuelven un valor un valor booleano. booleano. Para las cadenas, se pueden utilizar los operadores relacionales para comparaciones además de + y += para la concatenación: String nombre = "nombre" + "Apellido"; El operador = siempre hace copias de objetos, marcando los antiguos para borrarlos, y ya se encargará el garbage collector de devolver al sistema la memoria ocupada por el objeto eliminado. Separadores Sólo hay un par de secuencias con otros caracteres que pueden aparecer en el código Java; son los separadores simples, que van a definir la forma y función del código. Los separadores admitidos en Java son: () - paréntesis. Para contener listas de parámetros en la definición y llamada a métodos. También se utiliza para definir precedencia en expresiones, contener expresiones para control de flujo y rodear las conversiones de tipo. {} - llaves. Para contener los valores de matrices inicializadas automáticamente. También se utiliza para definir un bloque de código, para clases, métodos y ámbitos locales. [ ] - corchetes. Para declarar tipos matriz matriz.. También se utiliza cuando se referencian valores referencian valores de matriz matriz.. ; - punto y coma. Separa sentencias. , - coma. Separa identificadores consecutivos en una declaración de variables de variables.. También se utiliza para encadenar sentencias dentro de una sentencia for. . - punto. Para separar nombres de paquete de subpaquetes y clases. También se utiliza para separar una variable o método de una variable de referencia.
3.2 Control de Flujo Muchas de las sentencias de control del flujo del programa se han tomado del C: Sentencias de Salto if/else if( Boolean ) { sentencias; } else { sentencias; } switch switch( expr1 ) { case expr2:
sentencias; break; case expr3: sentencias; break; default: sentencias; break; } Sentencias de Bucle Bucles for for( expr1 inicio; expr2 test test;; expr3 incremento ) { sentencias; } El siguiente trocito de código Java que dibuja varias líneas en pantalla alternando sus colores entre rojo, azul y verde. Este fragmento sería parte de una función Java (método ( método): ): int contador; for( contador=1; contador <= 12; contador++ ) { switch( contador % 3 ) { case 0: setColor( Color Color.red .red ); break; case 1: setColor( Color Color.blue .blue ); break; case 2: setColor( Color Color.green .green ); break; } g.drawLine( 10,contador*10,80,contador*10 ); } También se soporta el operador coma (,) en los bucles for for( a=0,b=0; a < 7; a++,b+=2 ) Bucles while
while( Boolean ) { sentencias; } Bucles do/while do { sentencias; }while( Boolean ); Excepciones try-catch-throw try { sentencias; } catch( Exception ) { sentencias; } Java implementa excepciones para facilitar la construcción de código robusto. Cuando ocurre un error en un programa, el código que encuentra el error lanza una excepción, que se puede capturar y recuperarse de ella. Java proporciona muchas excepciones predefinidas. Control General del Flujo break [etiqueta] continue [etiqueta] return expr; etiqueta: sentencia; En caso de que nos encontremos con bucles anidados, se permite el uso de etiquetas para poder salirse de ellos, por ejemplo: uno: for( ) { dos: for( ) { continue; // seguiría en el bucle interno continue uno; // seguiría en el bucle principal break uno; // se saldría del bucle principal principal } } En el código de una función siempre hay que ser consecuentes con la declaración que se haya hecho de ella. Por ejemplo, si se declara una función
para que devuelva un entero, es imprescindible que se coloque un return final para salir de esa función, independientemente de que haya otros en medio del código que también provoquen la salida de la función. En caso de no hacerlo se generará un Warning, y el código Java no se puede compilar con Warnings. int func() { if( a == 0 ) return 1; return 0; // es imprescindible porque se retorna un entero }
3.3 Clases Las clases son lo más simple de Java. Todo en Java forma parte de una clase, es una clase o describe como funciona una clase. El conocimiento de las clases es fundamental para poder entender los programas Java. Todas las acciones de los programas Java se colocan dentro del bloque de una clase o un objeto. Todos los métodos se definen dentro del bloque de la clase, Java no soporta funciones o variables globales. Esto puede despistar a los programadores de C++, que pueden definir métodos fuera del bloque de la clase, pero esta posibilidad es más un intento de no separarse mucho y ser compatible con C, que un buen diseño orientado a objetos. Así pues, el esqueleto de cualquier aplicación Java se basa en la definición de una clase. Todos los datos básicos, como los enteros, se deben declarar en las clases antes de hacer uso de ellos. En C la unidad fundamental son los ficheros con código fuente, en Java son las clases. De hecho son pocas las sentencias que se pueden colocar fuera del bloque de una clase. La palabra clave import (equivalente al #include) puede colocarse al principio de un fichero, fuera del bloque de la clase. Sin embargo, el compilador reemplazará esa sentencia con el contenido del fichero que se indique, que consistirá, como es de suponer, en más clases. Tipos de Clases Hasta ahora sólo se ha utilizado la palabra clave public para calificar el nombre de las clases que hemos visto, pero hay tres modificadores más. Los tipos de clases que podemos definir son: abstract Una clase abstract tiene al menos un método abstracto. Una clase abstracta no se instancia, sino que se utiliza como clase base para la herencia herencia.. final Una clase final se declara como la clase que termina una cadena de herencia herencia.. No se puede heredar de una clase final. Por ejemplo, la clase Math es una clase final. public
Las clases public son accesibles desde otras clases, bien sea directamente o por herencia.. Son accesibles dentro del mismo paquete en el que se han declarado. herencia Para acceder desde otros paquetes, primero tienen que ser importadas. synchronizable Este modificador especifica que todos los métodos definidos en la clase son sincronizados, es decir, que no se puede acceder al mismo tiempo a ellos desde distintos threads; el sistema se encarga de colocar los flags necesarios para evitarlo. Este mecanismo hace que desde threads diferentes se puedan modificar las mismas variables mismas variables sin que haya problemas de que se sobreescriban.
3.4 Variables y Métodos de Instancia Una clase en Java puede contener variables y métodos. Las variables pueden ser tipos primitivos como int, char, etc. Los métodos son funciones funciones.. Por ejemplo, en el siguiente trozo de código podemos observarlo: public MiClase { int i; public MiClase() { i = 10; } public void Suma_a_i( int j ) { i = i + j; } } La clase MiClase contiene una variable (i) y dos métodos, MiClase que es el constructor de la clase y Suma_a_i( int j ). Ambito de una variable Los bloques de sentencias compuestas en Java se delimitan con dos llaves. Las variables de Java sólo son válidas desde el punto donde están declaradas hasta el final de la sentencia compuesta que la engloba. Se pueden anidar estas sentencias compuestas, y cada una puede contener su propio conjunto de declaraciones de variables locales. Sin embargo, no se puede declarar una variable con el mismo nombre que una de ámbito ámbito exterior. El siguiente ejemplo intenta declarar dos variables separadas con el mismo nombre. En C y C++ son distintas, porque están declaradas dentro de ámbitos diferentes. En Java, esto es ilegal. Class Ambito { int i = 1; // ámbito exterior { // crea un nuevo ámbito int i = 2; // error de compilación }
} Métodos y Constructores Los métodos son funciones que pueden ser llamadas dentro de la clase o por otras clases. El constructor es un tipo específico de método que siempre tiene el mismo nombre que la clase. Cuando se declara una clase en Java, se pueden declarar uno o más constructores opcionales que realizan la inicialización cuando s e instancia (se crea una ocurrencia) un objeto de dicha clase. Utilizando el código de ejemplo anterior, cuando se crea una nueva instancia de MiClase, se crean (instancian) todos los métodos y variables, y se llama al constructor de la clase: MiClase mc; mc = new MiClase(); La palabra clave new se usa para crear una instancia de la clase. Antes de ser instanciada con new no consume memoria, simplemente es una declaración de tipo. Después de ser instanciado un nuevo objeto mc, el valor el valor de i en el objeto mc será igual a 10. Se puede referenciar la variable (de instancia) i con el nombre del objeto: mc.i++; // incrementa la instancia de i de mc Al tener mc todas las variables y métodos de MiClase, se puede puede usar la primera sintaxis para llamar al método Suma_a_i() utilizando el nuevo nombre de clase mc: mc.Suma_a_i( 10 ); y ahora la variable mc.i vale 21. Finalizadores Java no utiliza destructores (al contrario que C++) ya que tiene una forma de recoger automáticamente todos los objetos que se salen del alcance. No obstante proporciona un método que, cuando se especifique en el código de la clase, el reciclador de memoria (garbage collector) llamará: // Cierra el canal cuando este objeto es reciclado protected void finalize() { close(); }
3.5 Alcance de Objetos y Reciclado de Memoria Los objetos tienen un tiempo de vida y consumen recursos durante el mismo. Cuando un objeto no se va a utilizar más, debería liberar el espacio que ocupaba en la memoria de forma que las aplicaciones no la agoten (especialmente las grandes). En Java, la recolección y liberación de memoria es responsabilidad de un thread llamado automatic garbage collector (recolector automático de basura de basura). ). Este
thread monitoriza el alcance de los objetos y marca y marca los objetos que se han salido de alcance. Veamos un ejemplo: String s; // no se ha asignado todavia s = new String( "abc" ); // memoria asignada s = "def"; // se ha asignado nueva memoria // (nuevo objeto) Más adelante veremos en detalle la clase String, pero una breve descripción de lo que hace esto es; crear un objeto String y rellenarlo con los caracteres "abc" y crear otro (nuevo) String y colocarle los caracteres "def". En esencia se crean dos objetos: Objeto String "abc" Objeto String "def" Al final de la tercera sentencia, el primer objeto objeto creado de nombre s que contiene "abc" se ha salido de alcance. No hay forma de acceder a él. Ahora se tiene un nuevo objeto llamado s y contiene "def". Es marcado y eliminado en la siguiente iteración del thread reciclador de memoria.
3.6 Herencia La Herencia es el mecanismo por el que se crean nuevos objetos definidos en términos de objetos ya existentes. Por ejemplo, si se tiene la clase Ave, se puede crear la subclase Pato, que es una especialización de Ave. class Pato extends Ave { int numero_de_patas; } La palabra clave extends se usa para generar una subclase (especialización) de un objeto. Una Pato es una subclase de Ave. Cualquier cosa que contenga la definición de Ave será copiada a la clase Pato, además, en Pato se pueden definir sus propios métodos y variables de instancia. Se dice que Pato deriva o hereda de Ave. Además, se pueden sustituir los métodos proporcionados proporcionados por la clase base. Utilizando nuestro anterior ejemplo de MiClase, aquí hay un ejemplo de una clase derivada sustituyendo a la función Suma_a_i(): import MiClase; public class MiNuevaClase extends MiClase { public void Suma_a_i( int j ) { i = i + ( j/2 ); } }
Ahora cuando se crea una instancia de MiNuevaClase, MiNuevaClase, el valor de i también se inicializa a 10, pero la llamada al método Suma_a_i() produce un resultado diferente: MiNuevaClase mnc; mnc = new MiNuevaClase(); mnc.Suma_a_i( 10 ); En Java no se puede hacer herencia múltiple. Por ejemplo, de la clase aparato con motor y de la clase animal no se puede derivar nada, sería como obtener el objeto toro mecánico a partir de una máquina motorizada (aparato con motor motor)) y un toro (aminal). En realidad, lo que se pretende es copiar los métodos, es decir, pasar la funcionalidad del toro de verdad al toro mecánico, con lo cual no sería necesaria la herencia múltiple sino simplemente la compartición de funcionalidad que se encuentra implementada en Java a través de interfaces.
3.7 Control de Acceso Cuando se crea una nueva clase en Java, se puede especificar el nivel de acceso que se quiere para las variables de instancia y los métodos definidos en la clase: public public void CualquieraPuedeAcceder(){} Cualquier clase desde cualquier lugar puede acceder a las variables y métodos de instacia públicos. protected protected void SoloSubClases(){} Sólo las subclases de la clase y nadie más puede acceder a las variables y métodos de instancia protegidos. private private String NumeroDelCarnetDeIdentidad; Las variables y métodos de instancia privados sólo pueden ser accedidos desde dentro de la clase. No son accesibles desde las subclases. friendly (sin declaración específica) void MetodoDeMiPaquete(){} MetodoDeMiPaquete(){} Por defecto, si no se especifica el control de acceso, las variables y métodos de instancia se declaran friendly (amigas), lo que significa que son accesibles por todos los objetos dentro del mismo paquete, pero no por los externos al paquete. Es lo mismo que protected. Los métodos protegidos (protected) pueden ser vistos por las clases derivadas derivadas,, como en C++, y también, en Java, por los paquetes (packages). Todas las clases de un paquete pueden ver los métodos protegidos de ese paquete. Para evitarlo, se deben declarar como private protected, lo que hace que ya funcione como en C++ en donde sólo se puede acceder a las variables y métodos protegidos de las clases derivadas derivadas..
3.8 Variables y Métodos Estáticos En un momento determinado se puede querer crear una clase en la que el valor de una variable de instancia sea el mismo (y de hecho sea la misma variable) para todos los objetos instanciados a partir de esa clase. Es decir, que exista una única copia de la variable de instancia. Se usará para ello la palabra clave static. class Documento extends Pagina { static int version = 10; } El valor de la variable version será el mismo para cualquier objeto instanciado de la clase Documento. Siempre que un objeto instanciado de Documento cambie la variable version, ésta cambiará para todos los objetos. De la misma forma se puede declarar un método como estático, lo que evita que el método pueda acceder a las variables de instancia no estáticas: class Documento extends Pagina { static int version = 10; int numero_de_capitulos; static void annade_un_capitulo() { numero_de_capitulos++; // esto no funciona } static void modifica_version( int i ) { version++; // esto si funciona funciona } } La modificación de la variable numero_de_capitulos no funciona porque se está violando una de las reglas de acceso al intentar acceder desde un método método estático a una variable no estática estática.. Todas las clases que se derivan, cuando se declaran estáticas, comparten la misma página de variables; es decir, todos los objetos que se generen comparten la misma zona de memoria. Las funciones estáticas se usan para acceder solamente a variables estáticas. class UnaClase { int var; UnaClase() { var = 5; } UnaFuncion() {
var += 5; } } En el código anterior, si se llama a la función UnaFuncion a través de un puntero a función, no se podría acceder a var, porque al utilizar un puntero a función no se pasa implícitamente el puntero al propio objeto (this). Sin embargo, sí se podría acceder a var si fuese estática estática,, porque siempre estaría en la misma posición de memoria para todos los objetos que se creasen de UnaClase.
3.9 this Y super Al acceder a variables de instancia de una clase, la palabra palabra clave this hace referencia a los miembros de la propia clase. Volviendo al ejemplo de MiClase, se puede añadir otro constructor de la forma siguiente: public class MiClase { int i; public MiClase() { i = 10; } // Este constructor establece el valor de i public MiClase( int valor ) { this.i = valor; // i = valor } public void Suma_a_i( int j ) { i = i + j; } } Aquí this.i se refiere al entero i en la clase MiClase. Si se necesita llamar al método padre dentro de una clase que ha reemplazado ese método, se puede hacer referencia al método padre con la palabra clave super: import MiClase; public class MiNuevaClase extends MiClase { public void Suma_a_i( int j ) { i = i + ( j/2 ); super.Suma_a_i( j ); } }
En el siguiente código, el constructor establecerá el valor de i a 10, después lo cambiará a 15 y finalmente el método Suma_a_i() de la clase padre (MiClase) lo dejará en 25: MiNuevaClase mnc; mnc = new MiNuevaClase(); mnc.Suma_a_i( 10 );
3.10 Clases Abstractas Una de las características más útiles de cualquier lenguaje orientado a objetos es la posibilidad de declarar clases que definen como se utiliza solamente, sin tener que implementar métodos. Esto es muy útil cuando la implementación es específica para cada usuario, pero todos los usuarios tienen que utilizar los mismos métodos. Un ejemplo de clase abstracta en Java es la clase Graphics: public abstract class Graphics { public abstract void drawLine( int x1,int y1,int x2, int y2 ); public abstract void drawOval( int x,int y,int width, int height ); public abstract void drawArc( int x,int y,int width, int height,int startAngle,int arcAngle ); ... } Los métodos se declaran en la clase Graphics, pero el código que ejecutará el método está en algún otro sitio: public class MiClase extends Graphics { public void drawLine( int x1,int y1,int x2,int y2 ) { } } Cuando una clase contiene un método abstracto tiene que declararse abstracta. No obstante, no todos los métodos de una clase abstracta tienen que ser abstractos. Las clases abstractas no pueden tener métodos privados (no se podrían implementar) ni tampoco estáticos. Una clase abstracta tiene que derivarse obligatoriamente, no se puede hacer un new de una clase abstracta. Una clase abstracta en Java es lo mismo que en C++ virtual func() = 0; lo que obliga a que al derivar de la clase haya que implementar forzosamente los métodos de esa clase abstracta.
3.11 Interfaces
Los métodos abstractos son útiles cuando se quiere que cada implementación de la clase parezca y funcione igual, pero necesita que se cree una nueva clase para utilizar los métodos abstractos. Los interfaces proporcionan un mecanismo para abstraer los métodos a un nivel superior. Un interface contiene una colección de métodos que se implementan en otro lugar. Los métodos de una clase son public, static y final. La principal diferencia entre interface y abstract es que un interface proporciona un mecanismo de encapsulación de los protocolos de los métodos sin forzar al usuario a utilizar la herencia. Por ejemplo: public interface VideoClip { // comienza la reproduccion del del video video void play(); // reproduce el clip en un bucle void bucle(); // detiene la reproduccion void stop(); } Las clases que quieran utilizar el interface VideoClip utilizarán la palabra implements y proporcionarán el código necesario para implementar los métodos que se han definido para el interface: class MiClase implements VideoClip { void play() { } void bucle() { } void stop() { } Al utilizar implements para el interface interface es como si se hiciese una acción de copiar-y-pegar del código del interface, con lo cual no se hereda nada, solamente se pueden usar los métodos. La ventaja principal del uso de interfaces es que una clase interface puede ser implementada por cualquier número de clases, permitiendo a cada clase
compartir el interfaz de programación sin tener que ser consciente de la implementación que hagan las otras clases que implementen el interface. class MiOtraClase implements VideoClip { void play() { } void bucle() { } void stop() { }
3.12 Métodos Nativos Java proporciona un mecanismo para la llamada a funciones C y C++ desde nuestro código fuente Java. Para definir métodos como funciones C o C++ se utiliza la palabra clave native. public class Fecha { int ahora; public Fecha() { ahora = time(); } private native int time(); static { System.loadLibrary( "time" ); } } Una vez escrito el código Java, se necesitan ejecutar los pasos siguientes para poder integrar el código C o C++: • •
•
•
•
Utilizar javah para crear un fichero de cabecera (.h) Utilizar javah para crear un fichero de stubs, es decir, que contiene la declaración de las funciones Escribir el código del método nativo en C o C++, es decir, rellenar el código de la función, completando el trabajo de javah al crear el fichero de stubs Compilar el fichero de stubs y el fichero .c en una librería de carga dinámica (DLL en Windows en Windows '95 o libXX.so en Unix) Ejecutar la aplicación con el appletviewer
Más adelante trataremos en profundidad los métodos nativos, porque añaden una gran potencia a Java, al permitirle integrar a través de librería dinámica cualquier algoritmo desarrollado en C o C++, lo cual, entre otras cosas, se utiliza como método de protección contra la descompilación completa del código Java.
3.13 Paquetes La palabra clave package permite agrupar clases e interfaces. Los nombres de los paquetes son palabras separadas por puntos y se almacenan en directorios que coinciden con esos nombres. Por ejemplo, los ficheros siguientes, que contienen código fuente Java: Applet.java, AppletContext.java, AppletContext.java, AppletStub.java, AppletStub.java, AudioClip.java contienen en su código la línea: package java.applet; Y las clases que se obtienen de la compilación de los ficheros ficheros anteriores, se encuentran con el nombre nombre_de_clase.class, en el directorio: java/applet Import Los paquetes de clases se cargan con la palabra clave import, especificando el nombre del paquete como ruta y nombre de clase (es lo mismo que #include de C/C++). Se pueden cargar varias clases utilizando un asterisco. import java.Date; import java.awt.*; Si un fichero fuente Java no contiene ningún package, se coloca en el paquete por defecto sin nombre. Es decir, en el mismo directorio que el fichero fuente, y la clase puede ser cargada con la sentencia import: import MiClase; Paquetes de Java El lenguaje Java proporciona una serie de paquetes que incluyen ventanas, utilidades, un sistema de entrada/salida general, herramientas y comunicaciones.. En la versión actual del JDK, los paquetes Java que se incluyen comunicaciones son: java.applet Este paquete contiene clases diseñadas para usar con applets. Hay una clase Applet y tres interfaces: AppletContext, AppletContext, AppletStub y AudioClip. AudioClip. java.awt El paquete Abstract Windowing Toolkit (awt) contiene clases para generar widgets y componentes GUI (Interfaz Gráfico de Usuario). Incluye las clases Button, Checkbox, Choice, Component, Graphics, Menu, Panel, TextArea y TextField. java.io
El paquete de entrada/salida contiene las clases de acceso a ficheros: FileInputStream y FileOutputSt FileOutputStream. ream. java.lang Este paquete incluye las clases del d el lenguaje Java propiamente dicho: Object, Thread, Exception, System, Integer, Float, Math, String, etc. java.net Este paquete da soporte a las conexiones del protocolo TCP/ TCP/IP IP y, además, incluye las clases Socket, URL y URLConnection. java.util Este paquete es una miscelánea de clases útiles para muchas cosas en programación. Se incluyen, entre otras, Date (fecha), Dictionary (diccionario (diccionario), ), Random (números aleatorios) y Stack (pila FIFO).
3.14 Referencias Java se asemeja mucho a C y C++. Esta similitud, evidentemente intencionada, es la mejor herramienta para los programadores, ya que facilita en gran manera su transición a Java. Desafortunadamente, tantas similitudes hacen que no nos paremos en algunas diferencias que son vitales. La terminología utilizada en estos lenguajes, a veces es la misma, pero hay grandes diferencias subyacentes en su significado. C tiene tipos de datos básicos datos básicos y punteros. C++ modifica un un poco este panorama y le añade los tipos referencia. Java también también especifica sus tipos primitivos, elimina cualquier tipo de punteros y tiene tipos referencia mucho más claros. Todo este maremágnum de terminología provoca cierta consternación, así que vamos a intentar aclarar lo que realmente realmente significa. Conocemos ya ampliamente todos los tipos básicos de datos datos:: datos base, integrados, primitivos e internos; que son muy semejantes en C, C++ y Java; aunque Java simplifica un poco su uso a los desarrolladores haciendo que el chequeo de tipos sea bastante más rígido. Además, Java añade los tipos boolean y hace imprescindible el uso de este tipo booleano booleano en sentencias condicionales.
4. PROGRAMAS BÁSICOS EN JAVA 4.1 Una mínima aplicación en java La aplicación más pequeña posible es la que simplemente imprimir un mensaje en la pantalla. Tradicionalmente, el mensaje suele ser "Hola Mundo!". Esto es justamente lo que hace el siguiente siguiente fragmento de código: // // Aplicación HolaMundo de ejemplo // class HolaMundoApp { public static void main( String args[] ) { System.out.println( "Hola Mundo!" ) ;
} } HolaMundo Vamos ver en detalle la aplicación anterior, línea línea a línea. Esas líneas de código contienen los componenetes mínimos para imprimir Hola Mundo! en la pantalla. // // Aplicación HolaMundo de ejemplo // Estas tres primera líneas son comentarios. Hay tres tipos de comentarios en Java, // es un comentario orientado a línea. class HolaMundoApp { Esta línea declara la clase HolaMundoApp. El nombre de la clase especificado en el fichero fuente se utiliza para crear un fichero nombredeclase.class en el directorio en el que se compila la aplicación. En nuestro caso, el compilador creará un fichero llamado HolaMundoApp.class. public static void main( String args[] ) { Esta línea especifica un método que el intérprete Java busca para ejecutar en primer lugar. Igual que en otros lenguajes, Java utiliza una palabra clave main para especificar la primera función a ejecutar. En este ejemplo tan simple no se pasan argumentos. public significa que el método main puede ser llamado por cualquiera, incluyendo el intérprete Java. static es una palabra clave que le dice al compilador que main se refiere a la propia clase HolaMundoApp y no a ninguna instancia de la clase. De esta forma, si alguien intenta hacer otra instancia de la clase, el método main no se instanciaría. void indica que main no devuelve nada. Esto Esto es importante ya que Java realiza realiza una estricta comprobación de tipos, incluyendo los tipos que se ha declarado que devuelven los métodos. args[] es la declaración de un array de Strings. Estos son los argumentos escritos tras el nombre de la clase en la línea de comandos comandos:: %java HolaMundoApp arg1 arg2 ... System.out.println( "Hola Mundo!" ); Esta es la funcionalidad de la aplicación. Esta línea muestra el uso de un nombre de clase y método. Se usa el método println() de la clase out que está en el paquete System. El método println() toma una cadena como argumento y la escribe en el stream de salida estándar; en este caso, la ventana donde se lanza la aplicación. }
} Finalmente, se cierran las llaves que limitan el método main() y la clase HolaMundoApp. Compilacion y Ejecucion de HolaMundo Vamos a ver a continuación como podemos ver el resultado resultado de nuestra primera aplicación Java en pantalla. Generaremos un fichero con el código fuente de la aplicación, lo compilaremos y utilizaremos el intérprete java para ejecutarlo. Ficheros Fuente Java Los ficheros fuente en Java terminan con la extensión ".java". Crear un fichero utilizando cualquier editor de texto ascii que tenga como contenido el código de las ocho líneas de nuestra mínima aplicación, y salvarlo en un fichero con el nombre de HolaMundoApp.java. Para crear los ficheros con código fuente Java no es necesario un procesador de textos, textos, aunque puede utilizarse siempre que tenga salida a fichero de texto plano o ascii ascii,, sino que es suficiente con cualquier otro editor. Compilación El compilador javac se encuentra en el directorio bin por debajo del directorio java, donde se haya instalado el JDK. Este Este directorio bin, si se han seguido las instrucciones de instalación, debería formar parte de la variable de entorno PATH del sistema. Si no es así, tendría que revisar la Instalación del JDK. El compilador de Java traslada el código fuente Java a byte-codes, que son los componentes que entiende la Máquina Virtual Java que está incluida en los navegadores con soporte Java y en appletviewer. Una vez creado el fichero fuente HolaMundoApp.java, se puede compilar con la línea siguiente: %javac HolaMundoApp.java Si no se han cometido errores al teclear ni se han tenido problemas con el path al fichero fuente ni al compilador, no debería aparecer mensaje alguno en la pantalla, y cuando vuelva a aparecer el prompt del sistema, se debería ver un fichero HolaMundoApp.class nuevo en el directorio donde se encuentra el fichero fuente. Si ha habido algún problema, en Problemas de compilación al final de esta sección, hemos intentado reproducir los que más frecuentemente se suelen dar, se pueden consultar por si pueden aportar un poco de luz al error que haya aparecido. Ejecución Para ejecutar la aplicación HolaMundoApp, hemos de recurrir al intérprete java, que también se encuentra en el directorio bin, bajo el directorio java. Se ejecutará la aplicación con la línea: %java HolaMundoApp
y debería aparecer en pantalla la respuesta de Java: %Hola Mundo! El símbolo % representa al prompt del sistema, y lo utilizaremos para presentar las respuestas que nos ofrezca el sistema como resultado de la ejecución de los comandos que se indiquen en pantalla o para indicar las líneas de comandos a introducir. Problemas de compilación A continuación presentamos una lista lista de los errores más frecuentes que se presentan a la hora de compilar un fichero con código fuente Java, nos basaremos en errores provocados sobre nuestra mínima aplicación Java de la sección anterior, pero podría generalizarse sin demasiados problemas. %javac: Command not found No se ha establecido correctamente la variable PATH del sistema para el compilador javac. El compilador javac se encuentra en el directorio bin, que cuelga del directorio java, que cuelga del directorio donde se haya instalado el JDK (Java Development Kit). %HolaMundoApp.java:3: Method printl(java.lang.String) not found in class java.io.PrintStream. System.out.printl( "HolaMundo!); ^ •
Error tipográfico, el método es println no printl.
%In class HolaMundoApp: main must be public and static •
Error de ejecución, se olvidó colocar la palabra static en la declaración del método main de la aplicación.
%Can´t find class HolaMundoApp Este es un error muy sutil. Generalmente significa que el nombre de la clase es distinto al del fichero que contiene el código fuente, con lo cual el fichero nombre_fichero.class que se genera es diferente del que cabría esperar. Por ejemplo, si en nuestro fichero de código fuente de nuestra aplicación HolaMundoApp.java colocamos en vez de la declaración actual de la clase HolaMundoApp, la línea: class HolaMundoapp { se creará un fichero HolaMundoapp.class, que es diferente del HolaMundoApp.class, que es el nombre esperado de la clase; la diferencia se encuentra en la a minúscula y mayúscula.
4.2 El Visor de applets de Sun (appletviewer) El visualizador de applets (appletviewer) es una aplicación que permite ver en funcionamiento applets, sin necesidad de la utilización de un navegador World Wide-Web como HotJava, Microsoft Explorer o Nescape. En adelante, recurriremos muchas veces a él, ya que el objetivo del tutorial es el lenguaje Java.
Applet La definición más extendida de applet, muy bien resumida por Patrick Naughton, indica que un applet es "una pequeña aplicación accesible en un servidor Internet, que se transporta por la red, se instala automáticamente y se ejecuta in situ como parte de un documento web". Claro que así la definición establece el entorno (Internet, Web, etc.). En realidad, un applet es una aplicación pretendidamente corta (nada impide que ocupe más de un gigabyte, a no ser el pensamiento de que se va a transportar por la red y una mente sensata) basada en un formato gráfico sin representación representación independiente: es decir, se trata de un elemento a embeber en otras aplicaciones; es un componente en su sentido estricto. Un ejemplo en otro ámbito de cosas podría ser el siguiente: Imaginemos una empresa,, que cansada de empezar siempre a codificar desde cero, diseña un empresa formulario con los datos básicos de una persona (nombre, dirección dirección,, etc.). Tal formulario no es un diálogo por sí mismo, pero se podría integrar en diálogos de clientes,, proveedores clientes proveedores,, empleados, etc. El hecho de que se integre estática (embebido en un ejecutable) o dinámicamente (intérpretes, DLLs, etc.) no afecta en absoluto a la esencia de su comportamiento como componente con que construir diálogos con sentido autónomo. Pues bien, así es un applet. Lo que ocurre es que, dado que no existe una base adecuada para soportar aplicaciones industriales Java en las que insertar nuestras miniaplicaciones (aunque todo se andará), los applets se han construido mayoritariamente, y con gran acierto comercial (parece), como pequeñas aplicaciones interactivas, con movimiento movimiento,, luces y sonido y sonido... ... en Internet. Llamadas a Applets con appletviewer Un applet es una mínima aplicación Java diseñada para ejecutarse en un navegador Web. Por tanto, no necesita preocuparse por un método main() ni en dónde se realizan las llamadas. El applet asume que el código se está ejecutando desde dentro de un navegador. El appletviewer se asemeja al mínimo navegador. Espera como argumento el nombre del fichero html que debe cargar, no se le puede pasar directamente un programa Java. Este fichero html debe contener una marca que especifica el código que cargará el appletviewer: El appletviewer crear un espacio de navegación, incluyendo un área gráfica, donde se ejecutará el applet, entonces llamará a la clase applet apropiada. En el
ejemplo anterior, el appletviewer cargará una clase de nombre HolaMundo y le permitirá trabajar en su espacio gráfico. Arquitectura de appletviewer El appletviewer representa el mínimo interfaz de navegación. En la figura se muestran los pasos que seguiría appletviewer para presentarnos el resultado de la ejecución del código de nuestra clase. Esta es una visión simplificada del appletviewer. La función principal de esta aplicación es proporcionar al usuario un objeto de tipo Graphics sobre el que dibujar, y varias funciones para facilitar el uso del objeto Graphics. Ciclo de vida de un Applet Cuando un applet se carga en el appletviewer, comienza su ciclo de vida,, que pasaría por las siguientes vida fases:
Se crea una instancia de la clase que controla el applet. En el ejemplo de la figura anterior, sería la clase HolaMundo.
El applet se incializa. El applet comienza a ejecutarse. El applet empieza a recibir llamadas. Primero recibe una llamada init (inicializar), seguida de un mensaje start (empezar) y paint y paint (pintar). Estas llamadas pueden ser recibidas asíncronamente.
4.3 Escribir Applets Java Para escribir applets Java, hay que utilizar una serie de métodos, algunos de los cuales ya se hay sumariado al hablar de los métodos del appletviewer, que es el visualizador de applets de Sun. Incluso Incluso para el applet más sencillo necesitaremos varios métodos. Son los que se usan para arrancar (start) y detener (stop) la ejecución del applet, para pintar (paint (paint)) y actualizar (update) la pantalla y para capturar la información que se pasa al applet desde el fichero HTML a través de la marca marca APPLET. APPLET. init ( ) Esta función miembro es llamada al crearse el applet. Es llamada sólo una vez. La clase Applet no hace nada en init(). Las clases derivadas deben sobrecargar este método para cambiar el tamaño durante su inicialización, y cualquier otra inicialización de los datos que solamente deba realizarse una vez. Deberían realizarse al menos las siguientes acciones acciones:: Carga de imágenes y y sonido sonido El resize del applet para que tenga su tamaño correcto Asignación de valores de valores a las variables globales Por ejemplo: public void init() { if( width < 200 || height < 200 ) resize( 200,200 ); valor_global1 = 0; valor_global2 = 100; // cargaremos imágenes en memoria sin mostrarlas // cargaremos música de fondo en memoria sin reproducirla } destroy ( ) Esta función miembro es llamada cuando el applet no se va a usar más. La clase Applet no hace nada en este método. Las clases derivadas deberían sobrecargarlo para hacer una limpieza final. Los applet multithread deberán usar destroy() para "matar" cuanquier thread del applet que quedase activo. start ( ) Llamada para activar el applet. Esta función miembro es llamada cuando se visita el applet. La clase Applet no hace hace nada en este método. Las clases derivadas deberían sobrecargarlo para comenzar una animación, sonido sonido,, etc.
public void start() { estaDetenido = false; // comenzar la reproducción de la música musicClip.play(); } También se puede utilizar start() para eliminar cualquier thread que se necesite. stop ( ) Llamada para detener el applet. Se llama cuando el applet desaparece de la pantalla. La clase Applet no hace nada en este método. Las clases derivadas deberían sobrecargarlo para detener la animación, el sonido sonido,, etc. public void stop() { estaDetenido = true; if( /* ¿se está reproduciendo música música?? */ ) musicClip.stop(); } resize ( int width,int height ) El método init() debería llamar a esta función miembro para establecer el tamaño del applet. Puede utilizar las variables ancho y alto, pero no es necesario. Cambiar el tamaño en otro sitio que no sea init() produce un reformateo de todo el documento y no se recomienda. En el navegador Netscape, el tamaño del applet es el que se indica en la marca APPLET del HTML, no hace caso a lo que se indique indique desde el código Java del applet. width Variable entera, su valor es el ancho definido definido en el parámetro WIDTH de la marca HTML del APPLET. Por defecto es el ancho del icono. height Variable entera, su valor es la altura altura definida en el parámetro HEIGHT de la marca HTML del APPLET. Por defecto es la altura del icono. Tanto width como height están siempre disponibles para que se puede chequear el tamaño del applet. Podemos retomar el ejemplo de init(): public void init() { if( width < 200 || height < 200 ) resize( 200,200 ); ... paint( Graphics g )
Se llama cada vez que se necesita refrescar el área de dibujo del applet. La clase Applet simplemente dibuja una caja caja con sombreado de tres dimensiones en el área. Obviamente, la clase derivada debería sobrecargar este método para representar algo inteligente en la pantalla. Para repintar toda la pantalla cuando llega un evento Paint Paint,, se pide el rectángulo sobre el que se va a aplicar paint paint() () y si es más pequeño que el tamaño real del applet se invoca a repaint(), que como va a hacer un update(), se actualizará toda la pantalla. Podemos utilizar paint paint() () para imprimir nuestro mensaje de bienvenida: void public paint( Graphics g ) { g.drawString( "Hola Java!",25,25 ); // Dibujaremos la imágenes que necesitemos } update( Graphics g ) Esta es la función que se llama realmente cuando se necesita actualizar la pantalla. La clase Applet simplemente limpia el área y llama al método paint(). Esta funcionalidad es suficiente en la mayoría de los casos. De cualquier forma, las clases derivadas pueden sustituir esta funcionalidad para sus propósitos. Podemos, por ejemplo, utilizar update() para modificar selectivamente partes del área gráfica sin tener que pintar el área completa: public void update( Graphics g ) { if( estaActualizado ) { g.clear(); // garantiza la pantalla limpia repaint(); // podemos usar el método padre: super.update() } else // Información adicional g.drawString( "Otra información",25,50 ); } repaint() A esta función se la debería llamar cuando el applet necesite ser repintado. No debería sobrecargarse, sino dejar que Java repinte completamente el contenido del applet. Al llamar a repaint(), sin parámetros, internamente internamente se llama a update() que borrará el rectángulo sobre el que se redibujará y luego luego se llama a paint(). Como a repaint() se le pueden pasar parámetros, se puede modificar el rectángulo a repintar. getParameter ( String attr )
Este método carga los valores parados al applet vía la marca APPLET de HTML. El argumento String es el nombre del parámetro que se quiere obtener. Devuelve el valor que se le haya asignado al parámetro; en caso de que no se le haya asignado ninguno, devolverá null. Para usar getParameter(), se define una cadena genérica. Una vez que se ha capturado el parámetro, se utilizan métodos de cadena o de números para convertir el valor obtenido al tipo adecuado. public void init() { String pv; pv = getParameter( " velocidad velocidad"" ); if( pv == null ) velocidad = 10; else velocidad = Integer.parseInt( pv ); } getDocumentBase ( ) Indica la ruta http http,, o el directorio del disco, de donde se ha recogido la página HTML que contiene el applet, es decir, el lugar donde está la hoja en todo Internet o en el disco. getCodeBase ( ) Indica la ruta http http,, o el directorio del disco, de donde se ha cargado el código bytecode que forma el applet, es decir, el lugar lugar donde está el fichero .class en todo Internet o en el disco. print ( Graphics g ) Para imprimir en impresora impresora,, al igual que paint() se puede utilizar print(), que pintará en la impresora el mapa de bits del dibujo dibujo..
5. EL DEPURADOR DE JAVA - jdb El depurador de Java, jdb es un depurador de línea de comandos comandos,, similar al que Sun proporciona en sus Sistemas Sistemas,, dbx. Es complicado de utilizar y un tanto críptico, por lo que, en principio, tiene escasa practicidad y es necesaria una verdadera emergencia para tener que recurrir a él. Trataremos por encima los comandos que proporciona el jdb, pero sin entrar en detalles de su funcionamiento, porque no merece la pena. Casi es mejor esperar a disponer de herramientas visuales para poder depurar con cierta comodidad nuestro código Java. Para poder utilizar el depurador, las aplicaciones Java deben estar compiladas con la opción de depuración activada, -g. Posteriormente se puede lanzar appletviewer con la opción de depuración, debug, y habremos puesto en marcha jdb.
5.1 Depurar HolaMundo
Hemos modificado nuestro applet de ejemplo para utilizarlo en nuestra sesión de ejemplo con el depurador. Se compilaría con el comando: %javac -g hm.java y el contenido de nuestro applet HolaMundo HolaMundo modificado y guardado en el fichero hm.java sería el siguiente: // // Applet HolaMundo de ejemplo, para depurar // import java.awt.Graphics; import java.applet.Applet; public class hm extends Applet { int i; public void paint( Graphics g ) { i = 10; g.drawString( "Hola Mundo!",25,25 ); } } Una vez compilado, iniciamos la sesión lanzando el visor de applets de Sun con la opción de depuración, utilizando el comando: %appletviewer -debug hm.html El fichero hm.html contiene las líneas mínimas para poder activar el applet, estas líneas son las que reproducimos: Se inicia pues la sesión con el depurador y vamos a ir reproduciendo lo que aparece en la pantalla a medida que vamos introduciendo comandos: %appletviewer -debug hm.html Loading jdb... 0xee301bf0:class(sun.applet.AppletViewer) >
5.2 Comando help El comando help proporciona una lista de los comandos que están disponibles en la sesión de jdb. Esta lista es la que sigue, en donde hemos aprovechado la presencia de todos los comandos para comentar la acción que cada uno de ellos lleva a cabo.
>help ** command list ** threads [threadgroup] -- lista threads thread -- establece el thread por defecto suspend [thread id(s)] -- suspende threads (por defecto, todos) resume [thread id(s)] -- continúa threads (por defecto, todos) where [thread id]|all -- muestra la pila de un thread threadgroups -- lista los grupos de threads threadgroup -- establece el grupo de thread actual print [id(s)] -- imprime un objeto o campo dump [id(s)] -- imprime toda la información del objeto locals -- imprime las variables locales de la pila actual classes -- lista las clases conocidas methods -- lista los métodos de una clase stop in . -- fija un punto de ruptura en un método stop at : -- establece un punto de ruptura en una línea up [n frames] -- ascender en la pila de threads down [n frames] -- descender en la pila de threads clear : -- eliminar un punto de ruptura step -- ejecutar la línea actual cont -- continuar la ejecución desde el punto de ruptura catch -- parar por la excepción especificada ignore -- ignorar la excepción especificada list [line number] -- imprimir código fuente use [source file path] -- ver o cambiar la ruta del fichero fuente memory -- informe del uso de la memoria load - carga la clase Java a ser depurada run - comienza la ejecución de la clase cargada !! - repite el último comando help (or ?) - lista los comandos exit (or quit) - salir del depurador >
5.3 Comando threadgroups
El comando threadgroups permite ver la lista de threads que se están ejecutando. Los grupos system y main deberían estar siempre corriendo. >threadgroups 1.(java.lang.ThreadGroup)0xee300068 system 2.(java.lang.ThreadGroup)0xee300a98 main >
5.4 Comando threads El comando threads se utiliza para ver la lista completa de los threads que se están ejecutando actualmente. >threads Group system: 1.(java.lang.Thread)0xee300098 clock handler cond 2.(java.lang.Thread)0xee300558 Idle thread run 3.(java.lang.Thread)0xee3005d0 sync Garbage Collector cond 4.(java.lang.Thread)0xee300620 Finalizer thread cond 5.(java.lang.Thread)0xee300a20 Debugger agent run 6.(java.tools.debug.BreakpointHandler)0xee300b58) 6.(java.tools.debug.Break pointHandler)0xee300b58) Breakpoint handler cond Group main: 7.(java.lang.Thread)0xee300048 main suspended >
5.5 Comando run El comando run es el que se utiliza para arrancar el appletviewer en la sesión de depuración. Lo teclearemos y luego volveremos a listar los threads que hay en ejecución. >run run sun.applet.AppletViewer hm.html running... main[1]threads threads Group sun.applet.AppletViewer. sun.applet.AppletViewer.main: main: 1.(java.lang.Thread)0xee3000c0 AWT-Motif running 2.(sun.awt.ScreenUpdater)0xee302ed0 ScreenUpdater cond. Waiting Group applet-hm.class: 3.(java.lang.Thread)0xee302f38 Thread-6 cond. Waiting main[1]
El visor de applets de Sun aparecerá en la pantalla y mostrará el conocido mensaje de saludo al Mundo. Ahora vamos a rearrancar el appletviewer con un punto de ruptura, para detener la ejecución del applet, y podamos seguir mostrando los comandos disponibles en el jdb. main[1]exit %appletviewer -debug hm.html Loading jdb... 0xee3009c8:class(sun.applet.AppletViewer) >stop in hm.paint Breakpoint set in hm.paint >run run sun.applet.AppletViewer hm.html running... Breakpoint hit: hm.paint(hm.java:9) AWT-Motif[1]
5.6 Comando where El comando where mostrará la pila de ejecución del applet. AWT-Motif[1]where [1]hm.paint(hm.java:9) [2]sun.awt.motif.MComponentPeer.paint(MComponenetPeer.java:109) [3]sun.awt.motif.MComponentPeer.handleExpose(MComponenetPeer.java:170 ) AWT-Motif[1]
5.7 Comando use El comando use nos informa del camino donde jdb va a buscar los ficheros fuentes que contienen el código Java de las clases que se están depurando. Por defecto, utilizará el camino que se especifique en la variable de entorno CLASSPATH. AWT-Motif[1]use /usr/local/java/classes: AWT-Motif[1]
5.8 Comando list El comando list mostrará el código fuente actual al comienzo del punto de ruptura que hayamos fijado. AWT-Motif[1]list 9 public void paint( Graphics g ) { 10 => i = 10;
11 g.drawString( "Hola Mundo!",25,25 ) ; 12 } 13 } AWT-Motif[1]
5.9 Comando dump El comando dump nos permitirá ahora ver el valor del objeto g pasado desde el appletviewer. AWT-Motif[1]dump g g = (sun.awt.motif.X11Graphics)0xee303df8 { int pData = 1342480 Color foreground = (java.awt.Color (java.awt.Color)0xee302378 )0xee302378 Font font = (java.awt.Font)0xee302 (java.awt.Font)0xee302138 138 int originX = 0 int originY = 0 float scaleX = 1 float scaleY = 1 Image image = null } AWT-Motif[1]
5.10 Comando step El comando step nos porporciona el método para ejecutar la línea actual, que estará siendo apuntada por el indicador si hemos utilizado el comando list. AWT-Motif[1]step Breakpoint hit: hm.paint(hm.java:11) AWT-Motif[1]list 9 public void paint( Graphics g ) { 10 i = 10; 11 => g.drawString( "Hola Mundo!",25,25 ); 12 } 13 } AWT-Motif[1]
6. AWT 6.1 Introducción al AWT AWT es el acrónimo del X Window Toolkit para Java, donde X puede ser cualquier cosa: Abstract, Alternative, Awkward, Another o Asqueroso; aunque
parece que Sun se decanta por Abstracto, seriedad por encima de todo. Se trata de una biblioteca una biblioteca de clases Java para el desarrollo de Interfaces de Usuario Gráficas. La versión del AWT que Sun proporciona con el JDK se desarrolló en sólo dos meses y es la parte más débil de todo lo que representa Java como lenguaje. El entorno que ofrece es demasiado simple, no se han tenido en cuenta las ideas de entornos gráficos novedosos, sino que se ha ahondado en estructuras orientadas a eventos eventos,, llenas de callbacks y sin soporte alguno del entorno para la construcción gráfica; veremos que la simple acción de colocar un dibujo sobre un botón se vuelve una tarea harto complicada. Quizá la presión de tener que lanzar algo al mercado haya tenido mucho que ver en la pobreza de AWT. JavaSoft, asegura que esto sólo era el principio y que AWT será multi-idioma, tendrá herramientas visuales, etc. En fin, al igual que dicen los astrólogos, el futuro nos deparará muchas sorpresas. La estructura básica del AWT se basa en Componentes y Contenedores. Estos últimos contienen Componentes posicionados a su respecto y son Componentes a su vez, de forma que los eventos pueden tratarse tanto en Contenedores como en Componentes, corriendo por cuenta del programador (todavía no hay herramientas de composición visual) el encaje de todas las piezas, así como la seguridad de tratamiento de los eventos adecuados. Nada trivial. No obstante y pese a ello, vamos a abordar en este momento la programación con el AWT para tener la base suficiente y poder seguir profundizando en las demás características del lenguaje Java, porque como vamos a ir presentando ejemplos gráficos es imprescindible el conocimiento del AWT. Mientras tanto, esperemos que JavaSoft sea fiel a sus predicciones y lo que ahora veamos nos sirva de base para migrar a un nuevo y maravilloso AWT.
6.2 Interface de Usuario La interface de usuario es la parte del programa que permite a éste interactuar con el usuario. Las interfaces de usuario pueden adoptar muchas formas, que van desde la simple línea de comandos hasta las interfaces interfaces gráficas que proporcionan las aplicaciones más modernas. La interface de usuario es el aspecto más importante de cualquier aplicación. Una aplicación sin un interfaz fácil, impide que los usuarios saquen el máximo rendimiento del programa. Java proporciona los elementos básicos para construir decentes interfaces de usuario a través del AWT. Al nivel más bajo, el sistema operativo operativo transmite información desde el ratón y el teclado como dispositivos de entrada al programa. El AWT fue diseñado pensando en que el programador no tuviese que preocuparse de detalles como controlar el movimiento del ratón o leer el teclado teclado,, ni tampoco atender a detalles como la escritura en pantalla. El AWT constituye una librería de clases orientada a objeto para cubrir estos recursos y y servicios servicios de bajo nivel. Debido a que el lenguaje de programación Java es independiente de la plataforma en que se ejecuten sus aplicaciones, el AWT también es independiente de la plataforma en que se ejecute. El AWT proporciona un conjunto de herramientas para la construcción de interfaces gráficas que tienen
una apariencia y se comportan de forma semejante en todas las plataformas en que se ejecute. Los elementos de interface proporcionados por el AWT están implementados utilizando toolkits nativos de las plataformas, preservando una apariencia semejante a todas las aplicaciones que se creen para esa plataforma. Este es un punto fuerte del AWT, pero también tiene la desventaja de que una interface gráfica diseñada para una plataforma, p lataforma, puede no visualizarse correctamente en otra diferente.
6.3 Estructura del AWT La estructura de la versión actual del AWT podemos resumirla en los puntos que exponemos a continuación: • •
•
•
•
•
•
Los Contenedores contienen Componentes, que son los controles básicos No se usan posiciones fijas de los Componentes, sino que están situados a través de una disposición controlada co ntrolada (layouts) El común denominador de más bajo nivel se acerca al teclado teclado,, ratón y manejo de eventos Alto nivel de abstracción respecto al entorno de ventanas ventanas en que se ejecute la aplicación (no hay áreas cliente cliente,, ni llamadas a X, ni hWnds, etc.) La arquitectura de la aplicación es dependiente del entorno de ventanas, en vez de tener un tamaño fijo Es bastante dependiente de la máquina m áquina en que se ejecuta la aplicación (no puede asumir que un diálogo tendrá el mismo tamaño en cada máquina) Carece de un formato de recursos. No se puede separar el código de lo que es propiamente interface. No hay ningún diseñador de interfaces (todavía)
6.4 Componentes y Contenedores Una interface gráfica está construida en base a elementos gráficos básicos, los Componentes. Típicos ejemplos de estos Componentes son los botones, barras de desplazamiento, etiquetas, listas, cajas de selección o campos de texto texto.. Los Componentes permiten al usuario interactuar con la aplicación y proporcionar información desde el programa al usuario sobre el estado del programa. En el AWT, todos los Componentes de la interface interface de usuario son instancias de la clase Component o uno de sus subtipos. Los Componentes no se encuentran aislados, sino agrupados dentro de Contenedores. Los Contenedores contienen y organizan la situación de los Componentes; además, los Contenedores son en sí mismos Componentes y como tales pueden ser situados dentro de otros Contenedores. También contienen el código necesario para el control de eventos eventos,, cambiar la forma del cursor o modificar el icono de la aplicación. En el AWT, todos los Contenedores son instancias de la clase Container o uno de sus subtipos. Los Componentes deben circunscribirse dentro del Contenedor que los contiene. Esto hace que el anidamiento de Componentes (incluyendo Contenedores) en Contenedores crean árboles de elementos, comenzando con un Contenedor en la raiz del árbol y expandiéndolo en sus ramas.
7. GRAFICOS 7.1 Objetos Gráficos
En páginas anteriores ya se ha mostrado cómo escribir applets, cómo lanzarlos y los fundamentos básicos de la presentación de información sobre ellos. Ahora, pues, querremos hacer cosas más interesantes que mostrar texto texto;; ya que cualquier página HTML puede mostrar texto. Para ello, Java proporciona la clase Graphics, que permite mostrar texto a través del método drawString(), pero también tiene muchos otros métodos de dibujo dibujo.. Para cualquier programador, es esencial el entendimiento de la clase Graphics, antes de adentrarse en el dibujo de cualquier cosa en Java. Esta clase proporciona el entorno de trabajo para cualquier operación gráfica que se realice dentro del AWT. Juega dos importantes papeles: por un lado, es el contexto gráfico, es decir, contiene la información que va a afectar a todas las operaciones gráficas, incluyendo los colores de fondo y texto, la fuente de caracteres, la localización y dimensiones del rectángulo en que se va a pintar, e incluso dispone de información sobre el eventual destino de las operaciones gráficas (pantalla o imagen imagen). ). Por otro lado, la clase Graphics proporciona métodos que permiten el dibujo de primitivas, figuras y la manipulación de fonts de caracteres y colores y colores.. También hay clases para la manipulación de imágenes, doble-buffering, etc. Para poder pintar, un programa necesita un contexto gráfico válido, representado por una instancia de la clase Graphics. Pero, como esta clase es abstracta, no se puede instanciar directamente; así que debemos crear un componente y pasarlo al programa como un argumento a los métodos paint() o update(). Los dos métodos anteriores, paint() y update(), junto con el método repaint() son los que están involucrados en la presentación de gráficos en pantalla. El AWT, para reducir el tiempo que necesitan necesitan estos métodos para realizar el repintado en pantalla de gráficos, tiene dos axiomas: •
•
Primero, el AWT repinta solamente aquellos Componentes que necesitan ser repintados, bien porque estuviesen cubiertos por otra ventana o porque se pida su repintado directamente Segundo, si un Componente estaba tapado y se destapa, el AWT repinta solamente la porción del Componente que estaba oculta
En la ejecución del applet que aparece a continuación, EjemploGraf.java, podemos observar como se realiza este proceso proceso.. Ignorar la zona de texto de la parte superior del applet de momento, y centrar la mirada en la parte coloreada. Utilizando otra ventana, tapar y destapar parte de la zona que ocupa el applet. Se observará que solamente el trozo de applet que estaba cubierto es el que se repinta. Yendo un poco más allá, solamente aquellos componentes que estén ocultos y se vuelvan a ver serán los que se repinten, sin tener en cuenta su posición dentro de la jerarquía de componentes.
La pantalla en Java se incrementa de izquierda a derecha y de arriba hacia abajo, tal como muestra la figura:
Los pixels de la pantalla son pues: posición 0 + ancho de la pantalla - 1. En los textos, el punto de inserción se encuentra en la línea base de la primera letra.
7.2 Métodos para Dibujos Vamos a presentar métodos para dibujar varias figuras figuras geométricas. Como estos métodos funcionan solamente cuando son invocados por una instancia válida de la clase Graphics, su ámbito de aplicación se restringe a los componentes que se utilicen en los métodos paint() y update(). Normalmente los métodos de dibujo de primitivas gráficas funcionan por pares: un método pinta la figura normal y el otro pinta la figura rellena. drawLine( x1,y1,x2,y2 ) drawRect( x,y,ancho,alto ) fillRect( x,y,ancho,alto ) clearRect( x,y,ancho.alto ) drawRoundRect( x,y,ancho,alto,anchoArco,altoArco ) fillRoundRect( x,y,ancho,alto,anchoArco,altoArco )
draw3DRect( x,y,ancho,alto,boolean elevado ) fill3DRect( x,y,ancho,alto,boolean elevado ) drawOval( x,y,ancho,alto ) fillOval( x,y,ancho,alto ) drawArc( x,y,ancho,alto,anguloInicio,anguloArco ) fillArc( x,y,ancho,alto,anguloInicio,anguloArco ) drawPolygon( int[] puntosX,int[] puntosY[],numPuntos ) fillPolygon( int[] puntosX,int[] puntosY[],numPuntos ) drawString( string s,x,y ) drawChars( char data[],offset,longitud,x,y ) drawBytes( byte data[],offset,longitud,x,y ) copyArea( xSrc,ySrc,ancho,alto,xDest,yDest )
7.3 Métodos para Imagenes Los objetos Graphics pueden mostrar imágenes a través del método: drawImage( Image img,int x,int y,ImageObserver observador ); Hay que tener en cuenta que el método drawImage() necesita un objeto Image y un objeto ImageObserver. Podemos cargar una imagen desde un fichero de dibujo (actualmente sólo se soportan formatos GIF y JPEG) con el método getImage(): Image img = getImage( getDocumentBase(),"fi getDocumentBase(),"fichero.gif" chero.gif" ); La forma de invocar al método getImage() es indicando un URL donde se encuentre el fichero que contiene la imagen que queremos presentar y el nombre de ese fichero: getImage( URL directorioImagen,String ficheroImagen ); Un URL común para el método getImage() es el directorio donde está el fichero HTML. Se puede acceder a esa localización a través del método getDocumentBase() de la clase Applet, como ya se ha indicado. Normalmente, se realiza el getImage() en el método init() del applet y se muestra la imagen cargada en el método paint(), tal como se muestra en el ejemplo siguiente: public void init() { img = getImage( getDocumentBase(),"pepe.gif" ); } public void paint( Graphics g ) { g.drawImage( img,x,y,this ); }
En el applet Imagen.java, podemos ver el ejemplo completo. Su ponemos en él la existencia del fichero "Imagenes/pepe.gif": import java.awt.*; import sun.awt.image.URLI s un.awt.image.URLImageSource; mageSource; import java.applet.Applet; public class Imagen extends Applet { Imagen pepe; public void init() { pepe = getImage( getDocumentBase(),"Imagenes/pepe. getDocumentBase(),"Imagenes/pepe.gif" gif" ); } public void paint( Graphics g ) { g.drawString( pepe,25,25,this ); } }
7.4 Sonido en Java Java también posee métodos predefinidos para reproducir sonido. El ordenador remoto no necesita tener un reproductor de audio; Java realizará la reproducción (evidentemente, el ordenador remoto, en donde se ejecuta el applet, necesitará disponer de hardware de sonido). Reproducción de sonido La forma más fácil de reproducir sonido es a través del método play(): play( URL directorioSonido,String ficheroSonido ); o, simplemente: play( URL unURLdeSonido ); Un URL común para el método play() es el directorio donde está el fichero HTML. Se puede acceder a esa localización a través del método getDocumentBase() de la clase Applet: play( getDocumentBase(),"sonido.au" ); para que esto funcione, el fichero de la clase y el fichero sonido.au deberían estar en el mismo directorio. Reproducción Repetitiva Se puede manejar el sonido como si de imágenes se tratara. Se pueden cargar y reproducir más tarde. Para cargar un clip de sonido, se utiliza el método getAudioClip(): AudoClip sonido; sonido = getAudioClip( getDocumentBase(),"risas.au getDocumentBase(),"risas.au"" ); Una vez que se carga el clip de sonido, se pueden utilizar tres métodos:
sonido.play(); para reproducir el clip de sonido. sonido.loop(); para iniciar la reproducción del clip de sonido y que entre en un blucle de reproducción, es decir, en una repetición automática del clip. sonido.stop(); para detener el clip de sonido que se encuentre en ese instante en reproducción.
7.5 Entrada por Ratón Una de las características más útiles que ofrece Java es el soporte directo de la interactividad. La aplicación puede reaccionar a los cambios producidos en el ratón, por ejemplo, sin necesidad de escribir ninguna línea de código para su control, solamente indicando qué se quiere hacer cuando el ratón haga algo. El evento más común en el ratón es el click. Este evento es gobernado por dos métodos: mouseDown() (botón pulsado) y mouseUp() (botón soltado). Ambos métodos son parte de la clase Applet, pero se necesita definir sus acciones asociadas, de la misma forma que se realiza con init() o con paint().
8. EXCEPCIONES EN JAVA 8.1 Manejo de Excepciones Vamos a mostrar como se utilizan las excepciones, reconvirtiendo reconvirtiendo nuestro applet de saludo a partir de la versión iterativa de HolaIte.java: import java.awt.*; import java.applet.Applet; public class HolaIte extends Applet { private int i = 0; private String Saludos[] = { "Hola Mundo!", "HOLA Mundo!", "HOLA MUNDO!!" }; public void paint( Graphics g ) { g.drawString( Saludos[i],25,25 ); i++; } } Normalmente, un programa termina con un mensaje de error cuando se lanza una excepción. Sin embargo, Java tiene mecanismos para excepciones que permiten ver qué excepción se ha producido e intentar recuperarse de ella.
Vamos a reescribir el método paint() de nuestra versión iterativa iterativa del saludo: public void paint( Graphics g ) { try { g.drawString( Saludos[i],25,25 ); } catch( ArrayIndexOutOfBoundsException e ) { g.drawString( "Saludos desbordado",25,25 ); } catch( Exception e ) { // Cualquier otra excepción System.out.println( e.toString() ); } finally { System.out.println( "Esto se imprime siempre!" ); } i++; } La palabra clave finally define un bloque de código que se quiere que sea ejecutado siempre, de acuerdo a si se capturó la excepción o no. En el ejemplo anterior, la salida en la consola, con i=4 sería: Saludos desbordado ¡Esto se imprime siempre!
8.2 Generar Excepciones en Java Cuando se produce un error se debería generar, o lanzar, una excepción. Para que un método en Java, pueda lanzar excepciones, hay que indicarlo expresamente. void MetodoAsesino() throws NullPointerException,CaidaException NullPointerException,CaidaException Se pueden definir excepciones propias, no hay por qué limitarse a las predefinidas; bastará con extender la clase Exception y proporcionar la funcionalidad extra que requiera el tratamiento de esa excepción. También pueden producirse excepciones no de forma explícita como en el caso anterior, sino de forma implícita cuando se realiza alguna acción ilegal o no válida. Las excepciones, pues, pueden originarse de dos modos: el programa hace algo ilegal (caso normal), o el programa explícitamente genera una excepción ejecutando la sentencia throw (caso menos normal). La sentencia throw tiene la siguiente forma: throw ObtejoExcepction; El objeto ObjetoException es un objeto de una clase que extiende la clase Exception. El siguiente código de ejemplo origina una excepción de división por cero:
class melon { public static void main( String[] a ) { int i=0, j=0, k; k = i/j; // Origina un error de division-by-zero } } Si compilamos y ejecutamos esta aplicación Java, obtendremos la siguiente salida por pantalla: > javac melon.java > java melon java.lang.ArithmeticException:: / by zero java.lang.ArithmeticException at melon.main(melon.java:5) Las excepciones predefinidas, como ArithmeticException, se conocen como excepciones runtime. Actualmente, como todas las excepciones son eventos eventos runtime, sería mejor llamarlas excepciones irrecuperables. Esto contrasta con las excepciones que generamos explícitamente, que suelen ser mucho menos severas y en la mayoría de los casos podemos recuperarnos de ellas. Por ejemplo, si un fichero no puede abrirse, preguntamos al usuario que nos indique otro fichero; o si una estructura de datos se encuentra completa, podremos sobreescribir algún elemento que ya no se necesite.
8.3 Excepciones Predefinidas Las excepciones predefinidas y su jerarquía de clases es la que se muestra en la figura:
Las siguientes son las excepciones predefinidas más frecuentes que se pueden encontrar: ArithmeticException Las excepciones aritméticas son típicamente el resultado de una división por 0: int i = 12 / 0; NullPointerException Se produce cuando se intenta acceder a una variable o método antes de ser definido:
class Hola extends Applet { Image img; paint( Graphics g ) { g.drawImage( img,25,25,this ); } } IncompatibleClassChangeException El intento de cambiar una clase afectada por referencias en otros objetos, específicamente cuando esos objetos todavía no han sido recompilados. ClassCastException El intento de convertir un objeto a otra clase que no es válida. y = (Prueba)x; // donde x no es de tipo Prueba NegativeArraySizeException Puede ocurrir si hay un error aritmético al intentar cambiar el tamaño de un array. OutOfMemoryException ¡No debería producirse nunca! El intento de crear un objeto con el operador new ha fallado por falta de memoria. Y siempre tendría que haber memoria suficiente porque el garbage collector se encarga de proporcionarla al ir liberando objetos que no se usan y devolviendo memoria al sistema. NoClassDefFoundException Se referenció una clase que el sistema es incapaz de encontrar. ArrayIndexOutOfBoundsException ArrayIndexOutOfBoun dsException Es la excepción que más frecuentemente se produce. Se genera al intentar acceder a un elemento de un array más allá de los límites definidos inicialmente para ese array. UnsatisfiedLinkException Se hizo el intento de acceder a un método nativo que no existe. Aquí no existe un método a.kk class A { native void kk(); } y se llama a a.kk(), cuando debería llamar llamar a A.kk(). InternalException Este error se reserva para eventos que no deberían ocurrir. Por definición, el usuario nunca debería ver este error y esta excepción no debería lanzarse.
8.4 Crear Excepciones Propias También podemos lanzar nuestras propias excepciones, extendiendo la clase System.exception. Por ejemplo, consideremos un programa cliente cliente//servidor servidor.. El código cliente se intenta conectar al servidor, y durante 5 segundos se espera a que conteste el servidor. Si el servidor no responde, el servidor lanzaría la excepción de timeout: Cualquier método que lance una excepción también debe capturarla, o declararla como parte de la interface del método. Cabe preguntarse entonces, el porqué de lanzar una excepción si hay que capturarla en el mismo método. La respuesta es que las excepciones no simplifican el trabajo del control de errores. Tienen la ventaja de que se puede tener muy localizado el control de errores y no tenemos que controlar millones de valores de valores de retorno, pero no van más allá.
8.5 Capturar Excepciones Las excepciones lanzadas por un método que pueda hacerlo deben recoger en bloque try/catch o try/finally. try Es el bloque de código donde se prevé que se genere una excepción. Es como si dijésemos "intenta estas sentencias y mira a ver si se produce una excepción". El bloque try tiene que ir seguido, seguido, al menos, por una cláusula catch o una una cláusula finally catch Es el código que se ejecuta cuando se produce la excepción. Es como si dijésemos "controlo cualquier excepción que coincida con mi argumento". En este bloque tendremos que asegurarnos de colocar código que no genere excepciones. Se pueden colocar sentencias catch sucesivas, cada una controlando una excepción diferente. No debería intentarse capturar todas las excepciones con una sola cláusula. Esto representaría un uso demasiado general, podrían llegar muchas más excepciones de las esperadas. En este caso es mejor dejar que la excepción se propague hacia arriba y dar un mensaje de error al usuario. Se pueden controlar grupos de excepciones, es decir, que se pueden controlar, a través del argumento, excepciones semejantes. s emejantes. La cláusula catch comprueba los argumentos en el mismo orden en que aparezcan en el programa. Si hay alguno que coincida, se ejecuta el bloque. El operador instanceof se utiliza para identificar exactamente cual ha sido la identidad de la excepción. finally
Es el bloque de código que se ejecuta siempre, haya o no excepción. Hay una cierta controversia entre su utilidad utilidad,, pero, por ejemplo, podría servir para hacer un log o un seguimiento de lo que está pasando, porque como se ejecuta siempre puede dejarnos grabado si se producen excepciones y nos hemos recuperado de ellas o no. Este bloque finally puede ser útil cuando no hay ninguna excepción. Es un trozo de código que se ejecuta independientemente de lo que se haga en el bloque try. Cuando vamos a tratar una excepción, se nos plantea el problema de qué acciones vamos a tomar. En la mayoría de los casos, bastará con presentar una indicación de error al usuario y un mensaje avisándolo de que se ha producido un error y que decida si quiere o no continuar con la ejecución del programa.
8.6 Propagacion de Excepciones La cláusula catch comprueba los argumentos en el mismo orden en que aparezcan en el programa. Si hay alguno que coincida, se ejecuta el bloque y sigue el flujo de control por el bloque finally (si lo hay) y concluye el el control de la excepción. Si ninguna de las cláusulas catch coincide con la excepción que se ha producido, entonces se ejecutará el código de la cláusula finally (en caso de que la haya). Lo que ocurre en este caso, es exactamente lo mismo que si la sentencia que lanza la excepción no se encontrase encerrada en el bloque try. El flujo de control abandona este método y retorna prematuramente al método que lo llamó. Si la llamada estaba dentro del ámbito de una sentencia try, entonces se vuelve a intentar el control de la excepción, y así continuamente. Veamos lo que sucede cuando una excepción no es es tratada en la rutina en donde se produce. El sistema Java busca un bloque try..catch más allá de la llamada, pero dentro del método que lo trajo aquí. Si la excepción se propaga de todas formas hasta lo alto de la pila de llamadas sin encontrar un controlador específico para la excepción, entonces la ejecución se detendrá dando un mensaje. Es decir, podemos suponer que Java nos está proporcionando un bloque catch por defecto, que imprime un un mensaje de error y sale. No hay ninguna sobrecarga en el sistema por incorporar sentencias try al código. La sobrecarga se produce cuando se genera la excepción. Hemos dicho ya que un método debe capturar las excepciones que genera, o en todo caso, declararlas como parte de su llamada, indicando a todo el mundo que es capaz de generar excepciones. Esto debe ser así para que cualquiera que escriba una llamada a ese método esté avisado de que le puede llegar una excepción, en lugar del valor de retorno normal. Esto permite al programador que llama a ese método, elegir entre controlar la excepción o propagarla hacia arriba en la pila de llamadas.
9. Threads y Multithreading Considerando el entorno multithread, cada thread (hilo, flujo de control del programa) representa un proceso individual ejecutándose en un sistema. A veces se les llama procesos ligeros o contextos de ejecución. Típicamente, cada thread controla un único aspecto dentro de un programa, como puede ser supervisar la entrada en un determinado periférico o controlar toda la
entrada/salida del disco. Todos los threads comparten los mismos recursos, al contrario que los procesos en donde cada uno tiene su propia copia de código y datos (separados unos de otros). Gráficamente, los threads se parecen en su funcionamiento a lo que muestra la figura siguiente:
9.1 Flujo en Programas Programas de flujo único Un programa de flujo único o mono-hilvanado (single-thread) utiliza un único flujo de control (thread) para controlar su ejecución. Muchos programas no necesitan la potencia o utilidad de múltiples flujos de control. Sin necesidad de especificar explícitamente que se quiere un único flujo de control, muchos de los applets y aplicaciones son de flujo único. Programas de flujo múltiple En nuestra aplicación de saludo, no vemos el thread que ejecuta nuestro programa. Sin embargo, Java posibilita la creación y control de threads explícitamente. La utilización de threads en Java, permite una enorme flexibilidad a los programadores a la hora de plantearse el desarrollo de aplicaciones. La simplicidad para crear, configurar y ejecutar threads, permite que se puedan implementar muy poderosas y portables aplicaciones/applets que no se puede con otros lenguajes de tercera generación. En un lenguaje orientado a Internet como es Java, esta herramienta es vital. Si se ha utilizado un navegador con soporte Java, ya se habrá visto el uso de múltiples threads en Java. Habrá observado que dos applet se pueden ejecutar al mismo tiempo, o que puede desplazarla página del navegador mientras el applet continúa ejecutándose. Esto no significa que el applet utilice múltiples threads, sino que el navegador es multithreaded. Las aplicaciones (y applets) multithreaded utilizan muchos contextos de ejecución para cumplir su trabajo. Hacen uso del hecho de que muchas tareas contienen subtareas distintas e independientes. Se puede utilizar un thread para cada subtarea. Mientras que los programas de flujo único pueden realizar su tarea ejecutando las subtareas secuencialmente, un programa multithreaded permite que cada thread comience y termine tan pronto como sea posible. Este comportamiento presenta una mejor respuesta a la entrada en tiempo real.
9.2 Creacion y Control de threads Creación de un Thread
Hay dos modos de conseguir threads en Java. Una es implementando la interface Runnable, la otra es extender la clase Thread. La implementación de la interface Runnable es la forma habitual de crear threads. Las interfaces proporcionan al programador una forma de agrupar el trabajo de infraestructura de una clase. Se utilizan para diseñar los requerimientos comunes al conjunto de clases a implementar. La interface define el trabajo y la clase, o clases, que implementan la interface realizan ese trabajo. Los diferentes grupos de clases que implementen la interface tendrán que seguir las mismas reglas de funcionamiento. Hay una cuantas diferencias entre interface y clase. Primero, una interface solamente puede contener métodos abstractos y/o variables estáticas y finales (constantes). Las clases, por otro lado, pueden implementar métodos y contener variables que no sean constantes. Segundo, una interface no puede implementar implementar cualquier método. Una clase que implemente una interface debe implementar todos los métodos definidos en esa interface. Una interface tiene la posibilidad de poder extenderse de otras interfaces y, al contrario que las clases, puede extenderse de múltiples interfaces. Además, una interface no puede ser instanciada con el operador new; por ejemplo, la siguiente sentencia no está permitida: Runnable a = new Runnable(); // No se permite El primer método de crear un thread es simplemente extender la clase Thread: class MiThread extends Thread { public void run() { ... } El ejemplo anterior crea una nueva clase MiThread que extiende la clase Thread y sobrecarga el método Thread.run() por su propia implementación. El método run() es donde se realizará todo el trabajo de la clase. Extendiendo la clase Thread, se pueden heredar los métodos y variables de la clase padre. En este caso, solamente se puede extender o derivar una vez de la clase padre. Esta limitación de Java puede ser superada a través de la implementación de Runnable: public class MiThread implements Runnable { Thread t; public void run() { // Ejecución del thread una vez creado } } En este caso necesitamos crear una instancia de Thread antes de que el sistema pueda ejecutar el proceso como un thread. Además, el método abstracto run() está definido en la interface Runnable tiene que ser implementado. La única diferencia entre los dos métodos es que este último es mucho más flexible. En el ejemplo anterior, todavía tenemos oportunidad de extender la clase MiThread,
si fuese necesario. La mayoría de las clases creadas que necesiten ejecutarse como un thread , implementarán la interface Runnable, ya que probablemente extenderán alguna de su funcionalidad a otras clases. No pensar que la interface Runnable está haciendo alguna cosa cuando la tarea se está ejecutando. Solamente contiene métodos abstractos, con lo cual es una clase para dar idea sobre el diseño de la clase Thread. De hecho, si vemos los fuentes de Java, podremos comprobar que solamente contiene un método abstracto: package java.lang; public interface Runnable { public abstract void run() ; } Y esto es todo lo que hay sobre la interface interface Runnable. Como se ve, una interface interface sólo proporciona un diseño para las clases que vayan a ser implementadas. En el caso de Runnable, fuerza a la definición del método run(), por lo tanto, la mayor parte del trabajo se hace en la clase Thread. Un vistazo un poco más profundo a la definición de la clase Thread nos da idea de lo que realmente está pasando: public class Thread implements Runnable { ... public void run() { if( tarea != null ) tarea.run() ; } } ... } De este trocito de código se desprende que la clase Thread también implemente la interface Runnable. tarea.run() se asegura de que la clase con que trabaja (la clase que va a ejecutarse como un thread) no sea nula y ejecuta el método run() de esa clase. Cuando esto suceda, el método run() de la clase hará que corra como un thread. Arranque de un Thread Las aplicaciones ejecutan main() tras arrancar. Esta es la razón de que main() sea el lugar natural para crear y arrancar otros threads. La línea de código: t1 = new TestTh( "Thread 1",(int)(Math.random()*2000) ); crea un nuevo thread. Los dos argumentos pasados representan el nombre del thread y el tiempo que queremos que espere antes de imprimir el mensaje. Al tener control directo sobre los threads, tenemos que arrancarlos arrancarlos explícitamente. En nuestro ejemplo con: t1.start();
start(), en realidad es un método oculto en el thread que llama al método run(). Manipulación de un Thread Si todo fue bien en la creación del thread, t1 debería contener un thread válido, que controlaremos en el método run(). Una vez dentro de run(), podemos comenzar las sentencias de ejecución como en otros programas. run() sirve como rutina main() para los threads; cuando run() termina, también lo hace el thread. Todo lo que queramos que haga el thread ha de estar dentro de run(), por eso cuando decimos que un método es Runnable, nos obliga a escribir un método run(). En este ejemplo, intentamos inmediatamente esperar durante una cantidad c antidad de tiempo aleatoria (pasada a través del constructor): sleep( retardo ); El método sleep() simplemente le dice al thread que duerma durante los milisegundos especificados. Se debería utilizar sleep() cuando se pretenda retrasar la ejecución del thread. sleep() no consume recursos del sistema mientras el thread duerme. De esta forma otros threads pueden seguir funcionando. Una vez hecho el retardo, se imprime el mensaje "Hola Mundo!" con el nombre del thread y el retardo. Suspensión de un Thread Puede resultar útil suspender la ejecución de un thread sin marcar un límite de tiempo. Si, por ejemplo, está construyendo un applet con un thread de animación, querrá permitir al usuario la opción de detener la animación hasta que quiera continuar. No se trata de terminar la animación, sino desactivarla. des activarla. Para este tipo de control de thread se puede utilizar el método suspend(). t1.suspend(); Este método no detiene la ejecución permanentemente. El thread es suspendido indefinidamente y para volver a activarlo de nuevo necesitamos realizar una invocación al método resume(): t1.resume(); Parada de un Thread El último elemento de control que se necesita sobre threads es el método stop(). Se utiliza para terminar la ejecución de un thread: t1.stop(); Esta llamada no destruye el thread, sino que detiene su ejecución. La ejecución no se puede reanudar ya con t1.start(). Cuando se desasignen las variables que se usan en el thread, el objeto thread (creado con new) quedará marcado para eliminarlo y el garbage collector se encargará de liberar la memoria que utilizaba. En nuestro ejemplo, no necesitamos detener explícitamente el thread. Simplemente se le deja terminar. Los programas más complejos necesitarán un control sobre cada uno de los threads que lancen, el método stop() puede utilizarse en esas situaciones.
Si se necesita, se puede comprobar si un thread está vivo o no; considerando vivo un thread que ha comenzado y no no ha sido detenido. t1.isAlive(); Este método devolverá true en caso de que el thread t1 esté vivo, es decir, ya se haya llamado a su método run() y no haya sido parado con un stop() ni haya terminado el método run() en su ejecución.
9.3 Estados de un thread Durante el ciclo de vida de un thread, éste se puede encontrar en diferentes estados. La figura siguiente muestra estos estados y los métodos que provocan el paso de un estado a otro. Este diagrama no es una máquina de estados finita, pero es lo que más se aproxima al funcionamiento real de un thread .
Nuevo Thread Cuando un thread está en este estado estado,, es simplemente un objeto Thread vacío. El sistema no ha destinado ningún recurso para él. Desde este estado solamente puede arrancarse llamando al método start(), o detenerse definitivamente, llamando al método stop(); la llamada a cualquier otro método carece de sentido y lo único que provocará será la generación de una excepción excepción de tipo IllegalThreadStateException. Ejecutable La llamada al método start() creará los recursos del sistema necesarios para que el thread puede ejecutarse, lo incorpora a la lista de procesos disponibles para ejecución del sistema y llama al método run() del thread. En este momento nos encontramos en el estado "Ejecutable" del diagrama diagrama.. Y este estado es Ejecutable y no En Ejecución, porque cuando el thread está aquí no esta corriendo. Muchos Muchos ordenadores tienen solamente un procesador lo que hace imposible que todos los threads estén corriendo al mismo tiempo. Java implementa un tipo de scheduling o lista de procesos, que permite que el procesador sea compartido entre todos los procesos o threads que se encuentran en la lista. Sin embargo, para nuestros propósitos, y en la mayoría de los casos, se puede considerar que este estado es realmente un estado "En Ejecución", porque la impresión que produce ante nosotros es que todos los procesos se ejecutan al mismo tiempo.
Cuando el thread se encuentra en este estado, todas las instrucciones de código que se encuentren dentro del bloque declarado para el método run(), se ejecutarán secuencialmente. Parado El thread entra en estado "Parado" cuando alguien llama al método suspend(), cuando se llama al método sleep(), cuando el thread está bloqueado en un proceso de entrada/salida o cuando el thread utiliza su método wait() para esperar a que se cumpla una determinada condición. Cuando ocurra cualquiera de las cuatro cosas anteriores, el thread estará Parado. Para cada una de los cuatro modos de entrada en estado Parado, hay una forma específica de volver a estado Ejecutable. Cada forma de recuperar ese estado es exclusiva; por ejemplo, si el thread ha sido puesto a dormir, una vez transcurridos los milisegundos que se especifiquen, él solo se despierta y vuelve a estar en estado Ejecutable. Llamar al método resume() mientras esté el thread durmiendo no serviría para nada. Los métodos de recuperación del estado Ejecutable, en función de la forma de llegar al estado Parado del thread, son los siguientes: • • •
•
Si un thread está dormido, pasado el lapso de tiempo Si un thread está suspendido, luego de una llamada al método resume() Si un thread está bloqueado en una entrada/salida, una vez que el comando E/S concluya su ejecución Si un thread está esperando por una condición, cada vez que la variable que controla esa condición varíe debe llamarse a notify() o notifyAll()
Muerto Un thread se puede morir de dos formas: por causas naturales o porque lo maten (con stop()). Un thread muere normalmente cuando concluye de forma habitual su método run(). Por ejemplo, en el siguiente trozo de código, el bucle while es un bucle finito -realiza -realiza la iteración 20 veces y termina-: El método isAlive() La interface de programación de la clase Thread incluye el método isAlive(), que devuelve true si el thread ha sido arrancado (con start()) y no ha sido detenido (con stop()). Por ello, si el método isAlive() devuelve false, sabemos que estamos ante un "Nuevo Thread" o ante un thread "Muerto". Si nos devuelve true, sabemos que el thread se encuentra en estado "Ejecutable" o "Parado". No se puede diferenciar entre "Nuevo Thread" y "Muerto", ni entre un thread "Ejecutable" o "Parado".
9.4 Comunicacion entre threads Otra clave para el éxito y la ventaja de la utilización de múltiples threads en una aplicación, o aplicación multithreaded, es que pueden comunicarse entre sí. Se pueden diseñar threads para utilizar objetos comunes, que cada thread puede manipular independientemente de los otros threads.
El ejemplo clásico de comunicación de threads es un modelo productor/consumidor productor/ consumidor.. Un thread produce una salida, que otro thread usa (consume), sea lo que sea esa salida. Vamos entonces a crear un productor, que será un thread que irá sacando caracteres por su salida; crearemos también un consumidor que ira recogiendo los caracteres que vaya sacando el productor y un monitor que controlará el proceso de sincronización entre los threads. Funcionará como una tubería, insertando el productor caracteres en un extremos y ley y ley éndolos éndolos el consumidor en el otro, con el monitor siendo la propia tubería.
11.METODOS NATIVOS Un método nativo es un método Java (una instancia de un objeto o una clase) cuya implementación se ha realizado en otro lenguaje de programación, por ejemplo, C. Vamos a ver cómo se integran métodos nativos en clases Java. Actualmente, el lenguaje Java solamente solamente proporciona mecanismos para integrar código C en programas Java. Veamos pues los pasos necesarios para mezclar código nativo C y programas Java. Recurriremos (¡Cómo no!) a nuestro saludo; en este caso, el programa HolaMundo tiene dos clases Java: la primera implementa el método main() y la segunda, HolaMundo, tiene un método nativo que presenta el mensaje de saludo. La implementación de este segundo método la realizaremos en C.
10.1 Escribir Código Java En primer lugar, debemos crear una clase Java, HolaMundo, que declare un método nativo. También debemos crear el programa principal que cree el objeto HolaMundo y llame al método nativo. Las siguientes líneas de código definen la clase HolaMundo, que consta de un método y un segmento estático de código: class HolaMundo { public native void presentaSaludo(); static { System.loadLibrary( "hola" ); } }
Podemos decir que la implementación del método presentaSaludo() de la clase HolaMundo está escrito en otro lenguaje, porque la palabra reservada native aparece como parte de la definición del método. Esta definición, proporciona solamente la definición para presentaSaludo() y no porporciona ninguna implementación para él. La implementación la proporcionaremos desde un fichero fuente separado, escrito en lenguaje C. C. La definición para presentaSaludo() también indica que el método es un método público, no acepta argumentos y no devuelve ningún valor. Al igual que cualquier otro método, los métodos nativos deben estar definidos dentro de una clase Java. El código C que implementa el método presentaSaludo() debe ser compilado en una librería dinámica y cargado en la clase Java que lo necesite. Esta carga, mapea la implementación del método nativo sobre su definición. El siguiente bloque de código carga la librería dinámica, en este caso hola. El sistema Java ejecutará un bloque de código estático de la clase cuando la cargue. Todo el código anterior forma parte del fichero HolaMundo.java, que contiene la clase HolaMundo. En un fichero separado, Main.java, vamos a crear una aplicación Java que instancie a la clase HolaMundo y llame al método nativo presentaSaludo(). class Main { public static void main( String args[] ) { new HolaMundo().presentaSaludo(); } } Como se puede observar, llamamos al método nativo del mismo modo que a cualquier otro método Java; añadimos el nombre del método al final del nombre del objeto con un punto ("."). El conjunto de paréntesis que sigue al nombre del método encierra los argumentos que se le pasen. En este caso, el método presentaSaludo() no recibe ningún tipo de argumento.
10.2 Compilar el Código Java Utilizaremos ahora el compilador javac para compilar el código Java que hemos desarrollado. Compilaremos los dos ficheros fuentes de código Java que hemos creado, tecleando los siguientes comandos: > javac HolaMundo.java > javac Main.java
10.3 Crear el Fichero de Cabecera Ahora debemos utilizar la aplicación javah javah para conseguir el fichero de cabecera .h. El fichero de cabecera define una estructura que representa la clase HolaMundo sobre código C y proporciona la definición de una función C para la implementación del método nativo presentaSaludo() definido en ese clase. Ejecutamos javah sobre la clase HolaMundo, con el siguiente comando: > javah HolaMundo
Por defecto, javah creará el nuevo fichero .h en el mismo directorio en que se encuentra el fichero .class, obtenido al compilar con javac el código fuente Java correspondiente a la clase. El fichero que creará, será un fichero de cabecera del mismo nombre que la clase y con extensión .h. Por ejemplo, el comando anterior habrá creado el fichero HolaMundo.h, cuyo contenido será el siguiente: /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class HolaMundo */ #ifndef _Included_HolaMundo #define _Included_HolaMundo typedef struct ClassHolaMundo { char PAD; /* ANSI C requires structures to have a least one member */ } ClassHolaMundo; HandleTo(HolaMundo); #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void HolaMundo_presentaSaludo(struct HolaMundo_presentaSaludo(struct HHolaMundo *); #ifdef __cplusplus } #endif #endif Este fichero de cabecera contiene la definición de una estructura llamada ClassHolaMundo. Los miembros de esta estructura son paralelos a los miembros de la clase Java correspondiente; es decir, los campos en la estructura corresponden a las variables de la clase. Pero como HolaMundo no tiene ninguna variable, la estructura se encuentra vacía. Se pueden utilizar los miembros de la estructura para referenciar a variables instanciadas de la clase desde las funciones C. Además de la estructura C similar a la clase Java, vemos que la llamada de la función C está declarada como: extern void HolaMundo_presentaSaludo( struct HHolaMundo *); Esta es la definición de la función C que deberemos escribir para implementar el método nativo presentaSaludo() de la clase HolaMundo. Debemos utilizar esa definición cuando lo implementemos. Si HolaMundo llamase a otros métodos nativos, las definiciones de las funciones también aparecerían aquí. El nombre de la función C que implementa el método nativo está derivado del nombre del paquete, el nombre de la clase y el nombre del método nativo. Así, el método nativo presentaSaludo() dentro de la clase HolaMundo es
HolaMundo_presentaSaludo(). En este ejemplo, no hay nombre de d e paquete porque HolaMundo se considera englobado dentro del paquete por defecto. La función C acepta un parámetro, aunque el método nativo definido en la clase Java no acepte ninguno. Se puede pensar en este parámetro como si fuese la variable this de C++. En nuestro nuestro caso, ignoramos el parámetro this.
10.4 Crear el Fichero de stubs Volvemos a utilizar la aplicación javah javah para crear el fichero de stubs, que contiene todas las declaraciones de métodos, con sus llamadas y argumentos, listos para que nosotros rellenemos el cuerpo de los métodos con los algoritmos que necesitemos implementar. Proporciona la unión entre la clase Java y su estructura C paralela. Para generar este fichero, debemos indicar el parámetro .stubs al ejecutar la aplicación javah sobre la clase HolaMundo, de la siguiente forma: > javah -stubs HolaMundo Del mismo modo que se generaba el fichero .h; el nombre del fichero de stubs será el nombre de la clase con la extensión .c. En nuestro ejemplo, será HolaMundo.c, y su contenido será el siguiente: /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Stubs for class HolaMundo */ /* SYMBOL: "HolaMundo/presentaSalu "HolaMundo/presentaSaludo()V", do()V", Java_HolaMundo_presentaSaludo_stub Java_HolaMundo_presentaSaludo_ stub */ __declspec(dllexport) stack_item *Java_HolaMundo_presentaSaludo_stub(stack_item *_P_,struct execenv *Java_HolaMundo_presentaSaludo_stub(stack_item *_EE_) { extern void HolaMundo_presentaSaludo(void *); (void) HolaMundo_presentaSaludo(_P HolaMundo_presentaSaludo(_P_[0].p); _[0].p); return _P_; }
10.5 Escribir la funcion C Escribiremos la función C para el método nativo en un fichero fuente de código C. La implementación será una función habitual C, que luego integraremos con la clase Java. La definición de la función C debe ser la misma que la que se ha generado con javah en el fichero HolaMundo.h. La implementación que proponemos la guardaremos en el fichero HolaImp.c, y contendrá las siguientes línea de código: #include #include "HolaMundo.h> #include
void HolaMundo_presentaSaludo( struct HHolaMundo HHolaMundo *this ) { printf( "Hola Mundo, desde el Tutorial de Java\n" ); return; } Como se puede ver, la implementación no puede ser más sencilla: hace una llamada a la función printf() para presentar el saludo y sale. En el código se incluyen tres ficheros de cabecera: StubsPreamble.h Proporciona la información para que el código C pueda interactuar con el sistema Java. Cuando se escriben métodos nativos, siempre habrá que incluir este fichero en el código fuente C. HolaMundo.h Es el fichero de cabecera que hemos generado para nuestra clase. Contiene la estructura C que representa la clase Java para la que estamos escribiendo el método nativo y la definición de la función para ese método nativo. stdio.h Es necesario incluirlo porque utilizamos la función printf() de la librería estándar de C, cuya declaración se encuentra en este fichero de cabecera.
10.6 Crear la Libreria Dinámica Utilizaremos el compilador C para compilar el fichero .h, el fichero de stubs y el fichero fuente .c; para crear una librería dinámica. Para crearla, utilizaremos el compilador C de nuestro sistema, haciendo que los ficheros HolaMundo.c y HolaImp.c generen una librería dinámica de nombre hola, que será la que el sistema Java cargue cuando ejecute la aplicación que estamos construyendo. Vamos a ver cómo generamos esta librería en Unix y en Windows Windows '95. Unix Teclearemos el siguiente comando: % cc -G HolaMundo.c HolaImp.c -o libhola.so En caso de que no encuentre el compilador los ficheros de cabecera, se puede utilizar el flag -I para indicarle el camino de búsqueda, por ejemplo: % cc -G -I$JAVA_HOME/ -I$JAVA_HOME/include include HolaMundo.c HolaImp.c -o libhola.so donde $JAVA_HOME es el directorio donde se ha instalado la versión actual del Java Development Kit. Windows '95 El comando a utilizar en este caso es el siguiente: c:\>cl HolaMundo.c HolaImp.c -Fhola.dll -MD -LD javai.lib
Este comando funciona con Microsoft Microsoft Visual Visual C++ C++ 2.x y posteriores. Si queremos indicar al compilador donde se encuentran los ficheros de cabecera y las librerías, tendremos que fijar dos variables de entorno: c:\>SET INCLUDE=%JAVAHOME% INCLUDE=%JAVAHOME%\include;%INCLUDE% \include;%INCLUDE% c:\>SET LIB=%JAVAHOME%\ LIB=%JAVAHOME%\lib;%LIB% lib;%LIB% donde %JAVAHOME% es el directorio donde se ha instalado la versión actual del Java Development Kit.
10.7 Ejecutar el Programa Y, por fin, utilizaremos utilizaremos el intérprete de Java, java, para ejecutar ejecutar el programa que hemos construido siguiendo todos los pasos anteriormente descritos. Si tecleamos el comando: > java Main obtendremos el resultado siguiente: % Hola Mundo, desde el Tutorial de Java Si no aparece este mensaje de saludo y lo que aparece en pantalla son expresiones como UnsatisfiedLinkError, es porque no tenemos fijado correctamente el camino de la librería dinámica que hemos generado. Este camino es la lista de directorios que el sistema Java utilizará para buscar las librerías que debe cargar. Debemos asegurarnos de que el directorio donde se encuentra nuestra librería hola recién creada, figura entre ellos. Si fijamos el camino correcto y ejecutamos de nuevo el programa, veremos que ahora sí obtenemos el mensaje de saludo que esperábamos. Con ello, hemos visto como integrar código C en programas Java. Quedan muchas cuestiones por medio, como la equivalencia de tipos entre Java y C, el paso de parámetros, el manejo de cadenas, etc. Pero eso supondría entrar en mucha más profundidad dentro de Java de la que aquí pretendemos (por ahora).
11. Entrada/Salida Estándar Los usuarios de Unix, y aquellos familiarizados con las líneas de comandos de otros sistemas como DOS, han utilizado un tipo de entrada/salida conocida comúnmente por entrada/salida estándar. El fichero de d e entrada estándar (stdin) es simplemente el teclado teclado.. El fichero de salida estándar (stdout) es típicamente la pantalla (o la ventana del terminal). El fichero de salida de error estándar (stderr) también se dirige normalmente a la pantalla, pero se implementa como otro fichero de forma que se pueda distinguir entre la salida normal y (si es necesario) los mensajes de error.
11.1 La clase System Java tiene acceso a la entrada/salida estándar a través de la clase System. En concreto concreto,, los tres ficheros que se implementan son: Stdin
System.in implementa stdin como una instancia de la clase InputStream. Con System.in, se accede a los métodos read() y skip(). El método read() permite leer un byte de la entrada. skip( long n ), salta n bytes de la entrada. Stdout System.out implementa stdout como una instancia de la clase PrintStream. Se pueden utilizar los métodos print() y println() con cualquier tipo básico Java como argumento. Stderr System.err implementa stderr de la misma forma que stdout. Como con System.out, se tiene acceso a los métodos de PrintStream. Vamos a ver un pequeño ejemplo de entrada/salida entrada/salida en Java. El código siguiente, miType.java, reproduce, o funciona como la utilidad cat de Unix o type de DOS: import java.io.*; class miType { public static void main( String args[] ) throws IOException { int c; int contador = 0; while( (c = System.in.read() ) != '\n' ) { contador++; System.out.print( (char)c ); } System.out.println(); // Línea en blanco System.err.println( "Contados "+ contador +" bytes en total." ); } }
11.2 Clases comunes de Entrada/Salida Además de la entrada por teclado y salida por pantalla, se necesita entrada/salida por fichero, como son: FileInputStream DataInputStream FileOutputStream DataOutputStream También existen otras clases para aplicaciones más específicas, que no vamos a tratar, por ser de un uso muy concreto muy concreto:: PipedInputStream BufferedInputStream
PushBackInputStream StreamTokenizer PipedOutputStream BufferedOutputStream
12. FICHEROS EN JAVA Todos los lenguajes de programación tienen alguna forma de interactuar con los sistemas de ficheros locales; Java no es una excepción. Cuando se desarrollan applets para utilizar en red, hay que tener en cuenta que la entrada/salida directa a fichero es una violación de seguridad de acceso. Muchos usuarios configurarán sus navegadores para permitir el acceso al sistema de ficheros, pero otros no. Por otro lado, si se está desarrollando una aplicación Java para uso interno, probablemente será necesario el acceso directo a ficheros. Antes de realizar acciones sobre un fichero, necesitamos un poco de información sobre ese fichero. La clase File proporciona muchas utilidades relacionadas con ficheros y con la obtención de información básica sobre esos ficheros.
12.1 Creación de un objeto File Para crear un objeto File nuevo, se puede utilizar cualquiera de los tres constructores siguientes: File miFichero; miFichero = new File( "/etc/kk" ); o miFichero = new File( "/etc","kk" ); o File miDirectorio = new File( "/etc" ); miFichero = new File( miDirectorio,"kk" ); El constructor utilizado depende a menudo de otros objetos File necesarios para el acceso. Por ejemplo, si sólo se utiliza un fichero en la aplicación, el primer constructor es el mejor. Si en cambio cambio,, se utilizan muchos ficheros desde un mismo directorio, el segundo o tercer constructor serán más cómodos. Y si el directorio o el fichero es una variable, el segundo constructor será el más útil.
12.2 Ficheros de Acceso Aleatorio A menudo, no se desea leer un fichero de principio principio a fin; sino acceder al fichero como una base una base de datos, datos, donde se salta de un registro a otro; cada uno en diferentes partes del fichero. Java proporciona una clase RandomAccessFile para este tipo de entrada/salida. Creación de un Fichero de Acceso Aleatorio
Hay dos posibilidades para abrir un fichero de acceso aleatorio: Con el nombre del fichero: miRAFile = new RandomAccessFile( String nombre,String modo ); Con un objeto File: miRAFile = new RandomAccessFile( File fichero,String modo ); El argumento modo determina si se tiene acceso de sólo lectura (r) o de lectura//escritura (r/w). Por ejemplo, se puede abrir un fichero de una base lectura una base de datos para actualización: RandomAccessFile miRAFile; miRAFile = new RandomAccessFile( "/tmp/kk.dbf","rw" ); Acceso a la Información Los objetos RandomAccessFile esperan información de lectura lectura//escritura de la misma manera que los objetos DataInput/DataOutput. DataInput/DataOutput. Se tiene acceso a todas las operaciones read() y write() de las clases DataInputStream y DataOutputStream. También se tienen muchos métodos para moverse dentro de un fichero: long getFilePointer(); Devuelve la posición actual del puntero del fichero void seek( long pos ); Coloca el puntero del fichero en una posición determinada. La posición se da como un desplazamiento en bytes desde el comienzo del fichero. La posición 0 marca el comienzo de ese fichero. long length(); Devuelve la longitud del fichero. La posición length() marca el final de ese fichero. Actualización de Información Se pueden utilizar ficheros de acceso aleatorio para añadir información a ficheros existentes: miRAFile = new RandomAccessFile( "/tmp/kk.log","rw" ); miRAFile.seek( miRAFile.length() ); // Cualquier write() que hagamos a partir de este punto del código // añadirá información al fichero Vamos a ver un pequeño ejemplo, Log.java, Log.java, que añade una cadena a un fichero existente: import java.io.*; // Cada vez que ejecutemos este programita, se incorporara una nueva // linea al fichero de log que se crea la primera vez que se ejecuta
// // class Log { public static void main( String args[] ) throws IOException { RandomAccessFile miRAFile; String s = "Informacion a incorporar\nTutorial de Java\n"; // Abrimos el fichero de acceso aleatorio miRAFile = new RandomAccessFile( "/tmp/java.log","rw" ); // Nos vamos al final del fichero miRAFile.seek( miRAFile.length() ); // Incorporamos la cadena al fichero miRAFile.writeBytes( s ); // Cerramos el fichero miRAFile.close(); } }
13. COMUNICACIONES EN JAVA 13.1 Modelo de Comunicaciones con Java En Java, crear una conexión socket TCP/IP TCP/IP se realiza directamente con el paquete java.net. A continuación mostramos un diagrama de lo que ocurre en el lado del cliente y del servidor:
El modelo de sockets más simple es: El servidor establece un puerto y espera durante un cierto tiempo (timeout segundos), a que el cliente establezca la conexión. Cuando el cliente solicite una conexión, el servidor abrirá la conexión socket con el método accept().
El cliente establece una conexión con la máquina host a través del puerto que se designe en puerto# . El cliente y el servidor se comunican con manejadores InputStream y OutputStream. Hay una cuestión al respecto de los sockets, que viene impuesta por la implementación del sistema de seguridad de Java. Actualmente, los applets sólo pueden establecer conexiones con el nodo desde el cual se transfirió su código. Esto está implementado en el JDK y en el intérprete de Java de Netscape. Esto reduce en gran manera la flexibilidad de las fuentes de datos disponibles para los applets. El problema si se permite que un applet se conecte a cualquier máquina de la red, es que entonces se podrían utilizar los applets para inundar la red desde un ordenador con un cliente Netscape del que no se sospecha y sin ninguna posibilidad de rastreo.
13.2 Clases Utiles en Comunicaciones Vamos a exponer otras clases que resultan útiles útiles cuando estamos desarrollando programas de comunicaciones comunicaciones,, aparte de las que ya se han visto. El problema es que la mayoría de estas clases se prestan a discusión, porque se encuentran bajo el directorio sun. Esto quiere decir que son implementaciones Solaris y, por tanto, específicas del Unix Solaris. Además su API no está garantizada, pudiendo cambiar. Pero, a pesar de todo, resultan muy interesantes y vamos a comentar un grupo de ellas solamente que se encuentran en el paquete sun.net. Socket Es el objeto básico en toda comunicación a través de Internet, bajo el protocolo TCP. Esta clase proporciona métodos para la entrada/salida a través de streams que hacen la lectura y y escritura escritura a través de sockets muy sencilla. ServerSocket Es un objeto utilizado en las aplicaciones servidor para escuchar las peticiones que realicen los clientes conectados a ese servidor. Este objeto no realiza el servicio,, sino que crea un objeto Socket en función del cliente para realizar toda servicio la comunicación a través de él. DatagramSocket La clase de sockets datagrama puede ser utilizada para implementar datagramas o fiables (sockets UDP), no ordenados. Aunque la comunicación por estos sockets es muy rápida porque no hay que perder tiempo estableciendo la conexión entre cliente y servidor. DatagramPacket Clase que representa un paquete datagrama conteniendo información de paquete, longitud de paquete, direcciones Internet y números de puerto. MulticastSocket Clase utilizada para crear una versión multicast de las clase socket datagrama. Múltiples clientes clientes//servidores pueden transmitir a un grupo multicast (un grupo g rupo de direcciones IP compartiendo el mismo número de puerto). NetworkServer
Una clase creada para implementar métodos y variables utilizadas en la creación de un servidor TCP/IP TCP/IP.. NetworkClient Una clase creada para implementar métodos y variables utilizadas en la creación de un cliente TCP/IP. SocketImpl Es un Interface que nos permite crearnos nuestro propio modelo de comunicación.. Tendremos que implementar sus métodos cuando la usemos. Si comunicación vamos a desarrollar una aplicación con requerimientos especiales de comunicaciones comunicaciones,, como pueden se la implementación de un cortafuegos (TCP es un protocolo no seguro seguro), ), o acceder a equipos especiales (como un lector de código de barras o un GPS diferencial), necesitaremos nuestra propia clase Socket.
14. ARQUITECTURA Modelo/Vista/Controlador La arquitectura MVC (Model/View/Controller) fue introducida como parte de la versión Smalltalk-80 del lenguaje de programación Smalltalk. Fue diseñada para reducir el esfuerzo de programación necesario en la implementación de sistemas múltiples y sincronizados de los mismos datos. Sus características principales son que el Modelo, las Vistas y los Controladores se tratan como entidades separadas; esto hace que cualquier cambio producido en el Modelo se refleje automáticamente en cada una de las Vistas. Además del programa ejemplo que hemos presentado al principio y que que posteriormente implementaremos, este modelo de arquitectura se puede emplear en sistemas de representación gráfica de datos, como se ha citado, o en sistemas CAD, en donde se presentan partes del diseño con diferente escala de aumento, en ventanas separadas. En la figura siguiente, vemos la arquitectura MVC en su forma más general. Hay un Modelo, múltiples Controladores que manipulan ese Modelo, y hay varias Vistas de los datos del Modelo, que cambian cambian cuando cambia el estado de ese Modelo.
Este modelo de arquitectura presenta varias ventajas: ventajas: Hay una clara separación entre los componentes de un programa; lo cual nos permite implementarlos por separado. Hay un API muy bien definido; cualquiera c ualquiera que use el API, podrá reemplazar r eemplazar el Modelo, la Vista o el Controlador, sin aparente dificultad.
La conexión entre el Modelo y sus Vistas es dinámica; se produce en tiempo de ejecución, no en tiempo de compilación. Al incorporar el modelo de arquitectura MVC a un diseño, las piezas de un programa se pueden construir por separado y luego unirlas en tiempo de ejecución. Si uno de los Componentes, posteriormente, se observa que funciona mal, puede reemplazarse sin que las otras piezas se vean afectadas. Este escenario contrasta con la aproximación monolítica típica de muchos programas Java. Todos tienen un Frame que contiene todos los elementos, un controlador de eventos, un montón de cálculos y la presentación del resultado. Ante esta perspectiva, hacer un cambio aquí no es nada trivial.
14.1 Definición de las partes El Modelo es el objeto que representa los datos del programa. Maneja los datos y controla todas sus transformaciones. El Modelo Modelo no tiene conocimiento específico de los Controladores o de las Vistas, ni siquiera contiene referencias a ellos. Es el propio sistema el que tiene encomendada la responsabilidad de mantener enlaces entre el Modelo y sus Vistas, y notificar a las Vistas cuando cambia el Modelo. La Vista es el objeto que maneja la presentación visual de los datos representados por el Modelo. Genera una representación visual del Modelo y muestra los datos al usuario. Interactúa con el Modelo a través de una referencia al propio Modelo. El Controlador es el objeto que proporciona significado a las ordenes del usuario, actuando sobre los datos representados por el Modelo. Cuando se realiza algún cambio cambio,, entra en acción, bien sea por cambios en la información del Modelo o por alteraciones de la Vista. Interactúa con el Modelo a través de una referencia al propio Modelo. Vamos a mostrar un ejemplo concreto concreto.. Consideremos como tal el sistema descrito en la introducción a este capítulo, una pieza geométrica en tres dimensiones, que representamos en la figura siguiente:
En este caso, la pieza central de la escena en tres dimensiones es el Modelo. El Modelo es una descripción matemática de los vértices y las caras que componen la escena. Los datos que describen cada vértice o cara pueden modificarse (quizás como resultado de una acción del usuario, o una distorsión de la escena, o un algoritmo de sombreado). Sin embargo, no tiene noción del punto de vista, método de presentación, perspectiva o fuente de luz luz.. El Modelo es una representación pura de los elementos que componen la escena. La porción del programa que transforma los datos dentro del Modelo en una presentación gráfica es la Vista. La Vista incorpora la visión del Modelo a la
escena; es la representación gráfica de la escena desde un punto de vista determinado, bajo condiciones de iluminación determinadas. El Controlador sabe que puede hacer el Modelo e implementa el interface de usuario que permite iniciar la acción. En este ejemplo, un panel de datos de entrada es lo único que se necesita, para permitir añadir, modificar o borrar vértices o caras de la figura. Trabajo enviado por:
Lucas email: lucas[arroba]2-cool.com
definicion de java
El Entorno de Programación Java es un proyecto de la compañía Sun Microsystems que presenta una posible aproximación a lo que serán s erán los lenguajes de programación p rogramación de los próximos años. Sus objetivos se resumen en dotar de d e herramientas de programación prog ramación adecuadas para desarrollar aplicaciones que se ejecuten en entornos heterogéneos, conectados a través de redes de comunicaciones. Estas aplicaciones deben ser eficientes, podrán crecer dinámicamente, dinámica mente, en función de las necesidades, y serán operativas op erativas en una gran variedad de ordenadores. Los principales resultados del proyecto Java son:
* Se ha desarrollado un nuevo lenguaje de programación, denominado Java, que utiliza desarrollo orientado a objetos. Su sintaxis está basada en C++ (para simplificar el aprendizaje), pero elimina la mayoría de los aspectos oscuros de este lenguaje: se elimina el preprocesador de C, los typedefs, las funciones, y los punteros (casi todo lo heredado de C).
El programador de Java exclusivamente puede utilizar desarrollo orientado a objetos; no existen las funciones, salvo como métodos de acceso a una clase. Las variables siempre están incluidas dentro de clases, para favorecer la encapsulación del código.
Sus librerías de objetos predefinidas (el equivalente a las librerías de funciones) proporcionan herramientas h erramientas para las comunicaciones comunica ciones a través de la red, diseño de interfaces de usuario, …
* El programador queda liberado del manejo de memoria, que tantos problemas produce en lenguajes como C. Los objetos obtienen un espacio de almacenamiento durante su creación, que es recuperado automáticamente cuando se destruyen.
Las aplicaciones Java pueden tener varias líneas de ejecución (threads) concurrente. La multitarea por threads está implementada en el propio lenguaje. *
Se ha modificado el proceso tradicional de compilación. Los programas Java se compilan y traducen a un formato denominado bytecodes –un formato intermedio de representación de las aplicaciones, que es independiente de la arquitectura del ordenador y de su sistema operativo. Para ejecutar aplicaciones Java en cualquier sistema, es necesario disponer de un software que interprete los bytecodes (un runtime de Java); sin embargo, el código de las aplicaciones es siempre el mismo.
Con Java se pueden desarrollar aplicaciones completas independientes (al estilo de los entornos de programación tradicionales), o bien applets, módulos que pueden ser insertados en otra aplicación (por ejemplo, en un cliente Web), para realizar una función concreta. En cualquier caso, se dispone de la capacidad de incorporar módulos (objetos) dinámicamente, a través de una red de comunicaciones, sin necesidad de repetir el proceso de enlazado de la aplicación global.
Los dos últimos puntos constituyen uno de los aspectos más novedosos de Java. Cualquier sistema que disponga de un runtime de Java es capaz de ejecutar sus aplicaciones. Por tanto, la única parte dependiente de la máquina es este módulo, que se desarrolla y optimiza en función de sus características. La posibilidad de incorporar dinámicamente objetos a una aplicación activa elimina muchos de los problemas derivados de actualizar software, ya que se puede disponer de un servidor central de aplicaci ones, del que se recogen módulos a medida que se necesitan.
________________________ ___________ _________________________ _________________________ _________________________ ___________________ _______
DEFINICION DE JAVA
Un programa java es una coleccion de clases. Algunas clases se escriben y algunas forman parte del lenguaje java. Un programa java debe contener un metodo estatido denominado main (). La evolución de la tecnología informática de la última década ha sido espectacular: ordenadores cada vez más rápidos, con enormes cantidades de memoria, redes de comunicaciones que permiten intercambios de información con cualquier lugar del mundo, aplicaciones cada vez más fáciles y potentes… Sin embargo, desde el punto de vista de la programación, las cosas no han cambiado demasiado; los principales problemas de un programador prog ramador de nuestros días día s se pueden resumir en los siguientes s iguientes puntos:
* Los lenguajes de programación no han evolucionado al mismo ritmo que la potencia de los ordenadores; se dispone de herramientas más potentes, sobre todo en la generación de interfaces de usuario, pero están lejos de las necesidades reales de un programador. Se necesita aumentar la capacidad de abstracción y mejorar la reutilización del código desarrollado. * Las herramientas de depuración de código disponibles no son capaces de dar soluciones adecuadas cuando el tamaño y la complejidad de los programas crecen. Se producen muchos errores, y éstos son difíciles de localizar.
Las tecnologías orientadas a objetos, utilizadas en lenguajes como C++, Ada o Visual Basic, son una posible solución, pero a menudo son difíciles de utilizar, ya que es necesario un cambio en la mentalidad del programador. * Las redes informáticas de empresas y centros de investigación están basadas, cada vez en mayor medida, en entornos heterogéneos, con sistemas operativos y herramientas de programación muy diversas. div ersas. El esfuerzo de portar una aplicación entre diferentes entornos es casi tan grande como el de reescribirla de nuevo. * Las aplicaciones basadas en sistemas centralizados son todavía muy utilizadas. Sin embargo, la descentralización de los puestos de trabajo, y la demanda de mayor potencia de cálculo sólo tiene una respuesta: respue sta: el uso de varios sistemas informáticos que colaboran en un fin común. * El mantenimiento de las aplicaciones instaladas en un sistema heterogéneo y distribuido es muy costosa, ya que implica operaciones de desarrollo, instalación y recompilación de programas, dependientes de cada entorno, que siempre producen efectos difíciles de prever.
HISTORIA DE JAVA
Java es un lenguaje de programación orientado a objetos desarrollado por Sun Microsystems a principio de los años 90´s. En Diciembre de 1950 Patrick Naughton, Naughton, ingeniero de Sun Microsystems, Microsystems , reclutó a varios colegas entre ellos James Gosling y Mike Sheridan para trabajar sobre un nuevo proyecto conocido como "El proyecto verde" . Con la ayuda de otros ingenieros, empezaron a trabajar en una pequeña oficina en Sand Hill Road en Menlo Park, California. California . Y así interrumpió todas las comunicaciones regulares con Sun y trabajó sin descanso durante 18 meses. Intentaban desarrollar una nueva tecnología para programar la siguiente generación de dispositivos inteligentes, inteligentes, en los que Sun veía un campo nuevo a explorar. Crear un lenguaje de programación fácil de aprender y de usar. En un principio se consideraba C++ como lenguaje a utilizar, pero tanto Gosling como Gosling como Bill Joy lo encontraron inadecuado. Gosling intentó Gosling intentó primero extender y modificar C++ resultando el lenguaje C++ ++ - (++ - porque se añadían y eliminaban características a C++), pero lo abandonó para crear un nuevo lenguaje desde cero al que llamo Oak (roble en inglés, según la versión mas aceptada, por el roble que veía através de la ventana de su despacho). El resultado fue un lenguaje que tenía similitudes con C, C++ y Objetive C y C y que no estaba ligado a un tipo de CPU concreta. Mas tarde, se cambiaría el nombre de Oak a Java, Java , por cuestiones de propiedad intelectural, al existir ya un lenguaje con el nombre de Oak. Se supone que le pusieron ese nombre mientras tomaban café (Java es nombre de un tipo de café, originario de Asia), aunque otros afirman que el nombre deriva de las siglas de James Gosling, Arthur Van Hoff, y Andy Bechtolsheim . En Agosto de 1991 Oak ya Oak ya corría sus primeros programas. Para 1992, 1992, el equipo ya había desarrollado un sistema en un prototipo llamado Star7 (*7), (*7), dispositivo parecido a una PDA, cuyo nombre venía de la combinación de teclas del teléfono de la oficina del Proyecto Green que permitía a los usuarios responder al teléfono desde cualquier lugar. Por su parte, el presidente de la compañía Sun, Scott McNealy, McNealy , se dio cuenta de forma oportuna y estableció el Proyecto Verde como una subsidiaria de Sun. Después de mostrar a Scott McNealy y Bill Joy los Joy los prototipos de bajo nivel del sistema, continuán con el desarrollo, incluyendo sistema operativo, Green OS; el lenguaje Oak, las librerías, alguna aplicación básica y el hardware, hasta que el 3 de septiembre de 1992 se termina el desarrollo y con ello el Proyecto Verde. Verde . De 1993 a 1994, 1994 , el equipo de Naughton se lanzó en busca de nuevas oportunidades en el mercado, mismas que se fueron dando mediante el sistema operativo base. La incipiente subsidiaria fracasó en sus intentos de ganar una oferta con Time-Warner, sin embargo el equipo concluyó que el mercado para consumidores electrónicos smart y las cajas Set-Up en particular, no eran del todo eficaces. La subsidiaria Proyecto verde fue amortizada por la compañía Sun a mediados de 1994. Afortunadamente, Afortunadamente, el cese cese del Proyecto Verde coincidió con el nacimiento del fenómeno mundial WEB. WEB. Al examinar las dinámicas de Internet, lo realizado por el ex equipo verde se adecuaba a este nuevo ambiente. Patrick Naughton procedió a la construcción del lenguaje de programación Java que se accionaba con un browser prototipo. El 29 de septiembre de 1994 se termina el desarrollo del
prototipo de HotJava. HotJava. Cuando se hace la demostración a los ejecutivos de Sun, esta vez, se reconoce el potencial de Java y se acepta el proyecto. Con el paso del tiempo HotJava se convirtió en un concepto práctico dentro del lenguaje Java y demostró que podría proporcionar multiplataformas para que el código pueda ser bajado y corrido del Host del World Wide Web y que de otra forma no son seguros. Una de las características de HotJava fue su soporte para los "applets", que son las partes de Java que pueden ser cargadas mediante una red de trabajo para después ejecutarlo localmente y así lograr soluciones dinámicas en computación acordes al rápido crecimiento del ambiente WEB. El 23 de mayo de 1995 1995,, en la conferencia SunWorld `95, John Gage, Gage , de Sun Microsystems, y Marc Andreessen, Andreessen , cofundador y vicepresidente de Netscape, anunciaban la versión alpha de Java, que en ese momento solo corría en Solaris, y el hecho de que Java iba a ser incorporado en Netscape Navigator, el navegador mas utilizado de Internet. Con la segunda alpha de Java en Julio, Julio , se añade el soporte para Windows NT y NT y en la tercera, en Agosto, para Windows 95. En enero de 1995 Sun formá la empresa Java Soft para Soft para dedicarse al desarrollo de productos basados en la tecnologías Java, y así trabajar con terceras partes para crear aplicaciones, herramientas, sistemas de plataforma y servicios para aumentar las capacidades del lenguaje. Ese mismo mes aparece la versión 1.0 del JDK. JDK. Netscape Communications decide apoyar a Java applets en Netscape Navigator 2.0. Ese fue el factor clave que lanzó a Java a ser conocido y famoso. Y como parte de su estrategia de crecimiento mundial y para favorecer la promoción de la nueva tecnología, Java Soft otorgó permisos para otras compañías para que pudieran tener acceso al código fuente y al mismo tiempo mejorar sus navegadores. También les permitía crear herramientas de desarrollo para programación Java y los facultaba para acondicionar máquinas virtuales Java (JVM), (JVM), a varios sistemas operativos. Muy pronto las licencias o permisos contemplaban prestigiosas firmas como: IBM, Microsoft Microsoft,, Symantec, Silicon Graphics, Oracle, Toshiba y Novell. Los apples Java (basados en JDK 1.02) son apoyados por los dos más populares navegadores web (Nestcape Navigator 3.0 y Microsoft Internet Explorer 3.0 . 3.0 . I.B.M./Lotus, Computer Asociates, Symantec, Symantec, Informix, Informix, Oracle, Sybase Sybase y otras poderosas poderosas empresas empresas de software están están construyendo Software 100% puro JAVA, por ejemplo el Corel Office que actualmente está en versión Beta. Los nuevos proyectos de Java son co-patrocinados por cientos de millones de dólares en capital disponible de recursos tales como la Fundación Java, Java , un fondo común de capital formado el verano pasado por 11 compañías, incluyendo Cisco Systems, IBM, Netscape y Oracle. Hoy en día, puede encontrar la tecnología Java en redes y dispositivos que comprenden desde Internet y superordenadores cientifícos hasta portátiles y teléfonos móviles; desde simuladores de mercado en Wall Street hasta juegos de uso doméstico y tarjetas de crédito: Java está en todas partes.
Versiones del lenguaje Java VERSIONES DE JAVA: JAVA:
JDK 1.0 (23 de enero de 1996) JDK 1.1 (19 de febrero de 1997). Una reestructuración intensiva del modelo de eventos AWT (Abstract Windowing Toolkit), clases internas (inner classes), JavaBeans, JDBC (Java Database Connectivity), para la integración de bases de datos, RMI (Remote Method Invocation). J2SE 1.2 (8 de dieciembre de 1998 - Nombre clave Playground. Esta y las siguientes versiones fueron recogidas bajo la denominación Java 2 y el nombre "J2SE" (Java 2 Platform, Standard Edition), reemplazó a JDK para distinguir la plataforma base de J2EE (Java 2 Platform, Enterprise Edition) y J2ME (Java 2 Platform, Micro Edition). La palabra reservada (keyword) strictfp. Reflexión en la programación. La API gráfica ( Swing) fue integrada en las clases básicas. La máquina virtual (JVM) de Sun fue equipada con un compilador JIT (Just in Time) por primera vez. Java Plug-in. Java IDL, una implementación de IDL (Interfaz para Descripción de Lenguaje) para la interoperabilidad con CORBA Colecciones (Collections) (Collections)
2SE 1.3 (8 de mayo de 2000) - Nombre clave Kestrel. La inclusión de la máquina virtual de HotSpot JVM (la JVM de HotSpot fue lanzada inicialmente en abril de 1999, para la JVM de J2SE 1.2) RMI fue cambiado para que se basara en CORBA. JavaSound Se incluyó el Java Naming and Directory Interface (JNDI) en el paquete de librerías principales (anteriormente disponible como una extensión). Java Platform Debugger Architecture (JPDA)
J2SE 1.4 (6 de febrero de 2002) - Nombre Clave Merlin. Este fue el primer lanzamiento de la plataforma Java desarrollado bajo el Proceso de la Comunidad Java como JSR 59. Los cambios más notables fueron: comunicado de prensalista completa de cambios. Palabra reservada assert (Especificado en JSR 41.) Expresiones regulares modeladas al estilo de las expresiones regulares Perl. Encadenación de excepciones Permite a una excepción encapsular la excepción de bajo nivel original. Non-blocking NIO (New Input/Output) (Especificado en JSR 51.) Logging API (Specified in JSR 47.) API I/O para la lectura y escritura escritura de imágenes imágenes en en formatos como como JPEG o PNG Parser XML integrado y procesador XSLT (JAXP) (Especificado en JSR 5 y JSR 63.) Seguridad integrada y extensiones criptográficas (JCE, JSSE, JAAS) Java Web Start incluido (El primer lanzamiento ocurrió en Marzo de 2001 para J2SE 1.3) (Especificado en JSR 56.)
J2SE 5.0 (30 de septiembre de 2004) - Nombre clave: Tiger. (Originalmente numerado 1.5, esta notación aún es usada internamente.[4]) Desarrollado bajo JSR 176, Tiger añadió un número significativo de nuevas características comunicado de prensa. Plantillas (genéricos) - provee conversion de tipos (type safety) en tiempo de compilación para colecciones y elimina la necesidad de la mayoría de conversion de tipos (type casting). (Especificado por JSR 14.) Metadatos - también llamados anotaciones, permite a estructuras del lenguaje como las clases o los métodos, ser etiquetados con datos adicionales, que puedan ser procesados posteriormente por utilidades de proceso de metadatos. (Especificado por JSR 175.)
Autoboxing/unboxing Autoboxing/unboxing - Conversiones Conversiones automáticas automáticas entre tipos tipos primitivos (Como (Como los int) y clases de envoltura primitivas (Como Integer). (Especificado por JSR 201.) Enumeraciones - la palabra reservada enum crea una typesafe, lista ordenada de valores (como Dia.LUNES, Dia.MARTES, etc.). Anteriormente, esto solo podía ser llevado a cabo por constantes enteras o clases construidas manualmente (enum pattern). (Especificado por JSR 201.) Varargs (número de argumentos variable) - El último parámetro de un método puede ser declarado con el nombre del tipo seguido por tres puntos (e.g. void drawtext(String... lines)). En la llamada al método, puede usarse cualquier número de parámetros de ese tipo, que serán almacenados en un array para pasarlos al metodo. Bucle for mejorado - La sintaxis para el bucle for se ha extendido con una sintaxis especial para iterar sobre cada miembro de un array o sobre cualquier clase que implemente Iterable, como la clase estándar Collection, de la siguiente forma: void displayWidgets (Iterable widgets) { for (Widget w : widgets) { w.display(); } } Este ejemplo itera sobre el objeto Iterable widgets, asignando, en orden, cada uno de los elementos a la variable w, y llamando al método display() de cada uno de ellos. (Especificado por JSR 201.)
Java SE 6 (11 de diciembre de 2006) - Nombre clave Mustang. Estuvo en desarrollo bajo la JSR 270. En esta versión, Sun cambió el nombre "J2SE" por Java SE y eliminó el ".0" del número de versión.[5]. Está disponible en http://java.sun.com/javase/6/ . Los cambios más importantes introducidos en esta versión son: Incluye un nuevo marco de trabajo y APIs que hacen posible la combinación de Java con lenguajes lenguajes dinámicos como PHP, Python, Ruby y JavaScript. Incluye el motor Rhino, de Mozilla, una implementación de Javascript en Java. Incluye un cliente completo de Servicios Web y soporta las últimas especificaciones para Servicios Web, como JAX-WS 2.0, JAXB 2.0, STAX y JAXP. Mejoras en la interfaz gráfica y en el rendimiento.
Java SE 7 - Nombre clave Dolphin. En el año 2006 aún se encontraba en las primeras etapas de planificación. Se espera que su desarrollo dé comienzo en la primavera de 2006, y se estima su lanzamiento para 2008.
Soporte para XML dentro del propio lenguaje Un nuevo concepto de superpaquete Soporte para closures Introducción de anotaciones estándar para detectar fallos en el software.
Además de de los cambios cambios en el lenguaje, lenguaje, con el paso de los años se han han efectuado muchos más cambios dramáticos en la librería de clases de Java (Java class library) que ha crecido de unos pocos cientos de clases en JDK 1.0 hasta más de tres mil en J2SE 5.0. APIs completamente nuevas, como Swing y Java2D, han sido introducidas y muchos de los métodos y clases originales de JDK 1.0 están desaprobados.
Los elementos del lenguaje Java Introducción
Identificadores
Comentarios Sentencias Bloques de código Expresiones Variables Los tipos básicos de datos Las cadenas de caractares o strings Palabras reservadas
La sintáxis de un lenguaje define los elementos de dicho lenguaje y cómo se combinan para formar un programa. progra ma. Los elementos típicos de cualquier cualq uier lenguaje son los siguientes: • • • • • • • •
Identificadores: los nombres que se dan a las variables Tipos de datos Palabras reservadas: las palabras que utiliza el propio lenguaje Sentencias Bloques de código Comentarios Expresiones Operadores
A lo largo de las páginas que siguen examinaremos en detalle cada uno de estos elementos.
Identificadores Un identificador es un nombre que identifica a una variable, a un método o función miembro, a una clase. Todos los lenguajes tienen ciertas reglas para componer los identificadores: •
• • • •
Todos los identificadores han de comenzar con una letra, el carácter subrayado ( _ ) o el carácter dollar ( $ ). Puede incluir, pero no comenzar por un número No puede incluir el carácter carácte r espacio en blanco Distingue entre letras mayúsculas y minúsculas No se pueden utilizar las plabras reservadas como identificadores
Además de estas restricciones, hay ciertas convenciones que hacen que el programa sea más legible, pero que no afectan a la ejecución del programa. La primera y fundamental es la de encontrar un nombre que sea significativo, de modo que el programa sea lo más legible posible. El tiempo que se pretende ahorrar eligiendo nombres cortos y poco significativos se pierde con creces cuando se revisa el programa después de cierto tiempo. Tipo de identificador
Convención
Ejemplo
nombre de una clase
Comienza por letra mayúscula
String, Rectangulo, CinematicaApplet
nombre de función
comienza con letra minúscula
calcularArea, getValue, setColor
nombre de variable
comienza por letra minúscula
area, color, appletSize
nombre de constante
En let letra rass mayú mayúsc scul ulas as
PI, MA MAX_A X_ANCHO NCHO
Comentarios Un comentario es un texto adicional que se añade al código para explicar su funcionalidad, bien a otras personas que lean el programa, o al propio autor como recordatorio. Los comentarios son una parte importante de la documentación de un programa. Los comentarios son s on ignorados por el compilador, c ompilador, por lo que no incrementan in crementan el tamaño del archivo ejecutable; se pueden por tanto, añadir libremente al código para que pueda entenderse mejor. La programación orientada a objetos facilita mucho la lectura del código, por lo que lo que no se precisa hacer tanto uso de los comentarios como en los lenguajes estructurados. En Java existen tres tipos de comentarios • • •
Comentarios en una sola línea Comentarios de varias líneas Comentarios de documentación
Como podemos observar un comentario en varias líneas es un bloque de texto situado entre el símbolo de comienzo del bloque /*, y otro de terminación del mismo */. Teniendo encuentra este hecho, los programadores diseñan comentarios como el siguiente: /*--------------------------------| | (C) Angel Franco García | | fecha: Marzo 1999 | | programa: PrimeroApp.java PrimeroApp.java | |---------------------------------*/
Los comentarios de documentación es un bloque de texto situado entre el símbolo de comienzo del bloque /**, y otro de terminación del mismo */. El programa javadoc utiliza estos comentarios para generar la documentación del código. /** Este es el primer programa de una serie dedicada a explicar los fundamentos del lenguaje Java */
Habitualmente, usaremos comentarios en una sola línea //, ya que no tiene el inconveniente de aprendernos los símbolos de comienzo y terminación del bloque, u olvidarnos de poner este último, dando lugar a un error en el momento de la compilación. En la ventana de edición del Entorno Integrado de Desarrollo (IDE) los comentarios se distinguen del resto del código por el color del texto. public class PrimeroApp{ public static void main(String[] args) { //imprime un mensaje System.out.println("El primer programa"); } }
Un procedimiento elemental de depuración de un programa consiste en anular ciertas sentencias de un programa mediante los delimitadores de comentarios. Por ejemplo, se puede modificar el programa pro grama y anular la sentencia senten cia que imprime el mensaje, poniendo ponien do delante de ella el delimitador de comentarios en una sola línea. //System.out.println("E //System.out.println("El l primer programa");
Al correr el programa, observaremos que no imprime nada en la pantalla. La sentencia System.out.println() imprime un mensaje en la consola, una ventana DOS que se abre en el escritorio de Windows 95. La función println tiene un sólo argumento una cadena de caracteres u objeto de la clase String .
Sentencias Una sentencia es una orden que se le da al programa para realizar una tarea específica, esta puede ser: mostrar un mensaje en la pantalla, declarar una variable (para reservar espacio en memoria), inicializarla, llamar a una función, etc. Las sentencias acaban con ;. este carácter separa una sentencia de la siguiente. Normalmente, las sentencias se ponen unas debajo de otras, aunque sentencias senten cias cortas pueden colocarse en una misma línea. He aquí algunos ejemplos de sentencias int i=1; import java.awt.*; System.out.println("El System.out.println("El primer programa"); rect.mover(10, 20);
En el lenguaje Java, los caracteres espacio en blanco se pueden emplear libremente. Como podremos ver en los sucesivos ejemplos, es muy importante para la legibilidad de
un programa la colocación de unas líneas debajo de otras empleando tabuladores. El editor del IDE nos ayudará plenamente en esta tarea sin apenas percibirlo.
Bloques de código Un bloque de código es un grupo de sentencias que se comportan como una unidad. Un bloque de código está es tá limitado por las llaves de apertura { y cierre }. Como ejemplos de bloques de código tenemos la definición de d e una clase, la definición de una función miembro, una sentencia iterativa for, los bloques try ... catch, para el tratamiento de las excepciones, etc.
Expresiones Una expresión es todo aquello que se puede poner a la derecha del operador asignación =. Por ejemplo: x=123; y=(x+100)/4; area=circulo.calcularArea(2.5); Rectangulo r=new Rectangulo(10, 10, 200, 300);
La primera expresión asigna un valor a la variable x. La segunda, realiza una operación La tercera, es una llamada a una función miembro calcularArea desde un objeto circulo de una clase determinada La cuarta, reserva espacio en memoria para un objeto de la clase Rectangulo mediante la llamada a una función especial denominada constructor.
Variables Una variable es un nombre que se asocia con una porción de la memoria del ordenador, en la que se guarda el valor asignado a dicha variable. Hay varios tipos de variables que requieren distintas cantidades de memoria para guardar datos. Todas las variables han de declararse antes de usarlas, la declaración consiste en una sentencia en la que figura el tipo de dato y el nombre que asignamos a la variable. Una vez declarada se le podrá asignar valores. Java tiene tres tipos de variables:
• • •
de instancia de clase locales
Las variables de instancia o miembros dato como veremos más adelante, se usan para guardar los atributos de un objeto particular. Las variables de clase o miembros dato estáticos son similares a las variables de instancia, con la excepción de que los valores que guardan son los mismos para todos los objetos de una determinada clase. En el siguiente ejemplo, PI es una variable de clase y radio es una variable de instancia. PI guarda el mismo valor para todos los objetos de la clase Circulo, pero el radio de cada círculo puede ser diferente class Circulo{ static final double PI=3.1416; double radio; //... }
Las variables locales se utilizan dentro de las funciones miembro o métodos. En el siguiente ejemplo area es una variable local a la función calcularArea en la que se guarda el valor del área de un objeto de la clase Circulo. Una variable local existe desde el momento de su definición hasta el final del bloque en el que se encuentra. class Circulo{ //... double calcularArea(){ calcularArea(){ double area=PI*radio*radio; return area; } }
En el lenguaje Java, las variables locales se declaran en el momento en el que son necesarias. Es una buena costumbre inicializar las variables en el momento en el que son declaradas. Veamos algunos ejemplos de declaración de algunas variables int x=0; String nombre="Angel"; double a=3.5, b=0.0, c=-2.4; boolean bNuevo=true; int[] datos;
Delante del nombre de cada variable se ha de especificar el tipo de variable que hemos destacado en letra negrita. Las variables pueden ser • • •
Un tipo de dato primitivo El nombre de una clase Un array
El lenguaje Java utiliza el conjunto de caracteres Unicode, que incluye no solamente el conjunto ASCII sino también carateres específicos de la mayoría de los alfabetos. Así, podemos declarar una un a variable que contenga conteng a la letra ñ
int año=1999;
Se ha de poner nombres significativos a las variables, generalmente formados por varias palabras combinadas, combinadas , la primera empieza por minúscula, minúscu la, pero las que le siguen sigu en llevan la letra inicial en mayúsculas. Se debe evitar en todos los casos nombres de variables cortos como xx, i, etc. double radioCirculo=3.2;
Las variables son uno de los elementos básicos de un programa, y se deben • • •
Declarar Inicializar Usar
Tipos de datos primitivos Tipo
Descripcion
boolean
Tiene dos valores true o false.
char
Caracteres Unicode de 16 bits Los caracteres alfa-numéricos son los mismos mismos que los ASCII con el bit alto puesto a 0. El intervalo de valores va desde 0 hasta 65535 (valores de 16-bits sin signo).
byte
Tamaño 8 bits. El intervalo de valores va desde -27 hasta 27 -1 (-128 a 127)
short
Tamaño 16 bits. El intervalo de valores va desde -215 hasta 215-1 (-32768 a 32767)
int
Tamaño 32 bits. El intervalo de valores va desde -231 hasta 231-1 (-2147483648 a 2147483647)
long
Tamaño 64 bits. El intervalo de valores va desde -263 hasta 263-1 (9223372036854775808 9223372036854775808 a 9223372036854775807) 9223372036854775807)
float
Tamaño 32 bits. Números en coma flotante de simple precisión. Estándar IEEE 7541985 (de 1.40239846e–45f 1.40239846e–45 f a 3.40282347e+38f) 3.40282347e+38 f)
double
Tamaño 64 bits. Números en coma flotante de doble precisión. Estándar IEEE 7541985. (de 4.94065645841246544e–324d 4.94065645841 246544e–324d a 1.7976931348623157e+308d.) 1.797693134862 3157e+308d.)
Los tipos básicos que utilizaremos en la mayor parte de los programas serán boolean, int y double.
Caracteres En Java los caracteres no están restringidos a los ASCII sino son Unicode. Un carácter está siempre rodeado de comillas simples como 'A', '9', 'ñ', etc. El tipo de dato char sirve para guardar estos caracteres. Un tipo especial de carácter es la secuencia de escape, similares a las del lenguaje C/C+ +, que se utilizan para representar caracteres de control o caracteres que no se
imprimen. Una secuencia de escape está formada por la barra invertida (\) y un carácter. En la siguiente tabla se dan las secuencias de escape más utilizadas. Carácter
Secuencia de escape
retorno de carro
\r
tabulador horizontal
\t
nueva línea
\n
barra invertida
\\
Variables booleanas En el lenguaje C/C++ el valor 0 se toma como falso y el 1 como verdadero. En el lenguaje Java existe el tipo de dato boolean. Una variable booleana solamente puede guardar uno de los dos posibles valores: true (verdadero) y false (falso). boolean encontrado=false; encontrado=false; {...} encontrado=true;
Variables enteras Una variable entera consiste en cualquier combinación de cifras precedidos por el signo más (opcional), para los positivos, o el signo menos, para los negativos. Son ejemplos de números enteros: 12, -36, 0, 4687, -3598 Como ejemplos de declaración de variable enteras tenemos: int numero=1205; int x,y; long m=30L;
int es la palabra reservada para declarar una variable entera. En el primer caso, el compilador reserva una porción de 32 bits de memoria en el que guarda el número 1205. Se accede a dicha porción de memoria mediante el nombre de la variable, numero. En el segundo caso, las porciones de memoria cuyos nombres son x e y, guardan cualquier valor entero si la variable es local o cero si la variable es de instancia o de clase. El uso de una variaable local antes de ser convenientemente inicializada puede conducir a consecuencias desastrosas. Por tanto, declarar e inicializar una variable es una práctica aconsejable.
En la tercera línea 30 es un número de tipo int por defecto, le ponemos el sufijo L en mayúsculas o minúsculas para indicar que es de tipo long. Existen como vemos en la tabla varios tipos de números enteros (byte, short, int, long), y también existe una clase denominada BigInteger cuyos objetos pueden guardar un número entero arbitrariamente grande.
Variables Variables en coma flotante Las variables del tipo float o double (coma flotante) se usan para guardar números en memoria que tienen parte entera y parte decimal. double PI=3.14159; double g=9.7805, c=2.9979e8;
El primero es una aproximación del número real π, el segundo es la aceleración de la gravedad a nivel del mar, el tercero es la velocidad de la luz en m/s, que es la forma de escribir 2.9979 108. El carácter punto '.', separa la parte entera de la parte decimal, en vez del carácter coma ',' que usamos habitualmente en nuestro idioma. Otras ejemplos son los siguientes float a=12.5f; float b=7f; double c=7.0; double d=7d;
En la primera línea 12.5 lleva el sufijo f , ya que por defecto 12.5 es double. En la segunda línea 7 es un entero y por tanto 7f es un número de tipo float. Y así el resto de los ejemplos. Conceptualmente, hay infinitos números de valores entre dos números reales. Ya que los valores de las variables se guardan en un número prefijado de bits, algunos valores no se pueden representar de forma precisa en memoria. Por tanto, los valores de las variables en coma flotante en un ordenador solamente se aproximan a los verdaderos números reales en matemáticas. La aproximación es tanto mejor, cuanto mayor sea el tamaño de la memoria que reservamos para guardarlo. De este hecho, surgen las variables del tipo float y double. Para números de precisión arbitararia se emplea la clase BigDecimal .
Valores constantes Cuando se declara una variable de tipo final, se ha de inicializar y cualquier intento de modificarla en el curso de la ejecución del programa da lugar a un error en tiempo de compilación.
Normalmente, las constantes de un programa se suelen poner en letras mayúsculas, mayúscula s, para distinguirlas de las que no son constantes. He aquí ejemplos de declaración de constantes. final double PI=3.141592653589793; final int MAX_DATOS=150; MAX_DATOS=150;
Las cadenas de caracteres o strings Además de los ocho tipos de datos primitivos, las variables en Java pueden ser declaradas para guardar una instancia de una clase, como veremos en el siguiente capítulo (Clases (Clases y objetos). objetos). Las cadenas de caracteres o strings son distintas en Java y en el lenguaje C/C++, en este último, las cadenas son arrays de caracteres terminados en el carácter '\0'. Sin embargo, en Java son objetos de la clase String . String mensaje="El primer programa";
Empleando strings, el primer programa quedaría de la forma equivalente public class PrimeroApp{ public static void main(String[] args) { //imprime un mensaje String mensaje="El primer programa"; System.out.println(mensaje); } }
En una cadena se pueden insertar caracteres especiales como el carácter tabulador '\t' o el de nueva línea '\n' String texto="Un string con \t un carácter tabulador y \n un salto de línea";
Palabras reservadas En el siguiente cuadro se listan las palabras reservadas, aquellas que emplea el lenguaje Java, y que el programador no puede utilizar como identificadores identificadores.. Algunas de estas palabras le resultarán familiares al programador programad or del lenguaje C/C++. Las palabras reservadas señaladas con un arterisco (*) no se utilizan. abstract
boolean
break
byte
byvalue*
case
cast*
catch
char
class
co n s t *
continue
default
do
d o ub l e
else
extends
false
final
finally
float
fo r
future*
generic*
goto*
if
implements
import
inner*
instanceof
int
interface
l on g
native
new
null
operator*
outer*
package
private
protected
public
rest*
return
short
satatic
super
switch
synchronized
th is
throw
transient
true
tr y
var*
vo i d
volatile
while
Las palabras reservadas se pueden clasificar en las siguientes categorías: • • • • • • •
Tipos de datos: boolean, float, double, int, char Sentencias condicionales: if, else, switch Sentencias iterativas: for, do, while, continue Tratamiento de las excepciones: try, catch, finally, throw Estructura de datos: class, interface, implements, extends Modificadores y control de acceso: public, private, protected, transient Otras: super, null, this.
Los operadores (aritméticos) Introducción
Los operadores aritméticos Concatenación de strings La precedencia de operadores La conversión automática y promoción Los operadores unarios
Todos los lenguajes de programación permiten realizar operaciones entre los tipos de datos básicos: suma, resta, producto, cociente, etc., de dos números. Otros lenguajes como el BASIC y Java permiten "sumar", concatenar cadenas de caracteres. En la página titulada "La primera aplicación", hemos aprendido a crear un poyecto un poyecto nuevo,, y la clase que describe la aplicación mínima que contiene la función estática nuevo main. Luego, le hemos añadido código para dar cierta funcionalidad a la aplicación, que ha consistido en imprimir un mensaje en la consola o mostrarlo en la ventana denominada Execution Log. Recordaremos que la imagen del disquette significa un proyecto nuevo cuyo nombre aparece en letra negrita, y cuyos componentes son archivos código fuente en el que se guardan las clases.
Los operadores aritméticos operador: OperadorAp.java
Java tiene cinco operadores aritméticos cuyo significado se muestra en la tabla adjunta Operado Operadorr Nombre Nombre
Ejemplo
+
Suma
3+4
-
Diferencia
3 -4
*
Producto
3* 4
/
Cociente
20 / 7
%
Módulo
20 %7
El cociente entre dos enteros da como resultado un entero. Por ejemplo, al dividir 20 entre 7 nos da como resultado 2. El operador módulo da como resultado el resto de la división entera. Por ejemplo 20%7 da como resultado 6 que es el resto de la división entre 20 y 7. El operador módulo también se puede emplear con números reales. Por ejemplo, el cociente entre 7.5 y 3.0 es 2.5 y el resto es cero, es decir, 7.5=3.0 x 2.5+ 0. El operador módulo, funciona de la siguiente forma 7.5=3.0 x 2+1.5, calcula la diferencia entre el dividendo (7.5) y el producto del divisor (3.0) por la parte entera (2) del cociente, devolviendo 1.5. Así pues, la operación 7.5%3.0 da como resultado 1.5.
El operador asignación
Nos habremos dado cuenta cuen ta que el operador más importante impo rtante y más frecuentemente usado es el operador asignación =, que hemos empleado para la inicialización de las variables. Así, int numero; numero=20;
la primera sentencia declara una variable entera de tipo int y le da un nombre (numero). La segunda sentencia usa el operador asignación para inicializar la variable con el número 20. Consideremos ahora, la siguiente sentencia. a=b;
que asigna a a el valor de b. A la izquierda siempre tendremos una variable tal como a, que recibe valores, a la derecha otra variable b, o expresión que tiene un valor. Por tanto, tienen sentido las expresiones a=1234; double area=calculaArea(radio); superficie=ancho*alto;
Sin embargo, no tienen sentido las expresiones 1234=a; calculaArea(radio)=area;
Las asignaciones múltiples son también posibles. Por ejemplo, es válida la sentencia c=a=b;
//equivalente //equivalente a c=(a=b);
la cual puede ser empleada para inicializar en la misma línea varias variables c=a=b=321;
//asigna 321 a a, b y c
El operador asignación se puede combinar con los operadores aritméticos Expresión
Significado
x+=y
x=x+y
x-=y
x=x-y
x*=y
x=x*y
x/=y
x=x/y
Así, la sentencia x=x+23;
evalúa la expresión x+23, que es asignada de nuevo a x. El compilador lee primero el contenido de la porción de memoria nombrada x, realiza la suma, y guarda el resultado
en la misma porción de memoria. Se puede escribir la sentencia anterior de una forma equivalente más simple x+=23;
Concatenación de strings En Java se usa el operador + para concatenar cadenas de carcateres o strings. Veremos en el siguiente apartado una sentencia como la siguiente: System.out.println("la temperatura centígrada es "+tC);
El operador + cuando se utiliza con strings y otros objetos, crea un solo string que contiene la concatenación de todos sus operandos. Si alguno de los operandos no es una cadena, se convierte automáticamente en una cadena. Por ejemplo, en la sentencia anterior el número del tipo double que guarda la variable tC se convierte en un string que se añade al string "la temperatura centígrada es ". Como veremos más adelante, un objeto se convierte automáticamente en un string si su clase redefine la función miembro toString de la clase base Object . Como vemos en el listado, para mostrar un resultado de una operación, por ejemplo, la suma de dos números enteros, escribimos iSuma=ia+ib; System.out.println("El resultado de la suma es "+iSuma);
Concatena una cadena de caracteres con un tipo básico de dato, que convierte automáticamente en un string. El operador += también funciona con cadenas. String nombre="Juan "; nombre+="García"; System.out.println(nombre);
public class OperadorAp { public static void main(String[] args) { System.out.println("Operaciones con enteros"); int ia=7, ib=3; int iSuma, iResto; iSuma=ia+ib; System.out.println("El resultado de la suma es "+iSuma); int iProducto=ia*ib; System.out.println("El resultado del producto es "+iProducto); System.out.println("El resultado del cociente es "+(ia/ib)); iResto=ia%ib; System.out.println("El resto de la división entera es "+iResto);
System.out.println("**********************************"); System.out.println("Operaciones con números decimales"); double da=7.5, db=3.0; double dSuma=da+db; System.out.println("El resultado de la suma es "+dSuma); double dProducto=da*db; System.out.println("El resultado del producto es "+dProducto); double dCociente=da/db; System.out.println("El resultado del cociente es "+dCociente); double dResto=da%db; dResto=da%db; System.out.println("El resto de la división es "+dResto); } }
La precedencia de operadores precede: PrecedeApp.java
El lector conocerá que los operadores aritméticos tienen distinta precedencia, así la expresión a+b*c
es equivalente a a+(b*c)
ya que el producto y el cociente tienen mayor precedencia que la suma o la resta. Por tanto, en la segunda expresión el paréntesis no es necesario. Sin embargo, si queremos que se efectúe antes la suma que la multiplicación tenemos de emplear los paréntesis (a+b)*c
Para realizar la operación
escribiremos
a/(b*c);
o bien, a/b/c;
En la mayoría de los casos, la precedencia de las operaciones es evidente, sin embargo, en otros que no lo son tanto, se aconseja emplear paréntesis. Como ejemplo, estudiemos un programa que nos permite convertir una temperatura en grados Fahrenheit en su equivalente en la escala Celsius. La fórmula de conversión es
cuya codificación es tC=(tF-32)*5/9;
Las operaciones se realizan como suponemos, ya que si primero se realizase el cociente 5/9, el resultado de la división entera sería cero, y el producto por el resultado de evaluar el paréntesis sería también cero. Si tenemos dudas sobre la precedencia de operadores podemos escribir tC=((tF-32)*5)/9; public class PrecedeApp { public static void main(String[] args) { int tF=80; System.out.println("la temperatura Fahrenheit es "+tF); int tC=(tF-32)*5/9; System.out.println("la temperatura centígrada es "+tC); } }
La conversión automática y promoción (casting) Cuando se realiza una operación, si un operando es entero (int) y el otro es de coma flotante (double) el resultado es en coma flotante (double). int a=5; double b=3.2; double suma=a+b;
Cuando se declaran dos variables una de tipo int y otra de tipo double. int entero; double real=3.20567; real=3.20567;
¿qué ocurrirá cuando asignamos a la variable entero el número guardado en la variable ?. Como hemos visto se trata de dos tipos de variables distintos cuyo tamaño en real ?. memoria es de 32 y 64 bits respectivamente. Por tanto, la sentencia entero=real;
convierte el número real en un número entero eliminando los decimales. La variable entero guardará el número 3. Se ha de tener cuidado, ya que la conversión de un tipo de dato en otro es una fuente frecuente de error entre los programadores principiantes. Ahora bien, supongamos que deseamos calcular la división 7/3, como hemos visto, el resultado de la división entera es 2, aún en el caso de que tratemos de guardar el resultado en una variable del tipo double, como lo prueba la siguiente porción de código.
int ia=7; int ib=3; double dc=ia/ib;
Si queremos obtener una aproximación decimal del número 7/3, hemos de promocionar el entero ia a un número en coma flotante, mediante un procedimiento denominado promoción o casting . int ia=7; int ib=3; double dc=(double)ia/ib;
Como aplicación, consideremos el cálculo del valor medio de dos o más números enteros int edad1=10; int edad2=15; double media=(double)(edad1+edad2)/2;
El valor medio de 10 y 15 es 12.5, sin la promoción se obtendría el valor erróneo 12. Imaginemos ahora, una función que devuelve un entero int y queremos guardarlo en una variable de tipo float. Escribiremos float resultado=(float)retorn resultado=(float)retornaInt(); aInt();
Existen también conversiones implícitas realizadas por el compilador, por ejemplo cuando pasamos un entero int a una función cuyo único parámetro es de tipo long.
Los operadores unarios unario: UnarioApp.java
Los operadores unarios son: • •
++ Incremento -- Decremento
actúan sobre un único operando. Se trata de uno de los aspecto más confusos para el programador, ya que el resultado r esultado de la operación depende de que el operador op erador esté a la derecha i++ o a la izquierda ++i. Conoceremos, primero el significado de estos dos operadores a partir de las sentencias equivalentes: i=i+1; i++;
Del mismo modo, lo son
//añadir 1 a i
i=i-1; i--;
//restar 1 a i
Examinemos ahora, la posición del operador respecto del operando. Consideremos en primer lugar que el operador oper ador unario ++ está a la derecha d erecha del operando. La sentencia sen tencia j=i++;
asigna a j, el valor que tenía i. Por ejemplo, si i valía 3, después de ejecutar la sentencia, j toma el valor de 3 e i el valor de 4. Lo que es equivalente a las dos sentencias j=i; i++;
Un resultado distinto se obtiene si el operador ++ está a la izquierda del operando j=++i;
asigna a j el valor incrementado de i. Por ejemplo, si i valía 3, después de ejecutar la sentencia j e i toman el valor de 4. Lo que es equivalente a las dos sentencias ++i; j=i; public class UnarioApp { public static void main(String[] args) { int i=8; int a, b, c; System.out.println("\tantes\tdurante\tdespués"); i=8; a=i; b=i++; c=i; System.out.println("i++\t"+a+'\t'+b+'\t'+c); i=8; a=i; b=i--; c=i; System.out.println("i--\t"+a+'\t'+b+'\t'+c); i=8; a=i; b=++i; c=i; System.out.println("++i\t"+a+'\t'+b+'\t'+c); i=8; a=i; b=--i; c=i; System.out.println("--i\t"+a+'\t'+b+'\t'+c); } }
La salida del programa es, la siguiente
i++ i-++i --i
antes 8 8 8 8
durante 8 8 9 7
de después 9 7 9 7
La primera columna (antes) muestra el valor inicial de i, la segunda columna (durante) muestra el valor de la expresión, y la última columna (después) muestra el valor final de i, después de evaluarse la expresión.
Se deberá de tener siempre el cuidado de inicializar la variable, antes de utilizar los operadores unarios con dicha variable.
Los operadores (relacionales) Introducción
Los operadores relacionales Los operadores lógicos
Los operadores relacionales relacion: RelacionApp.java
Los operadores relacionales son símbolos que se usan para comparar dos valores. Si el resultado de la comparación es correcto la expresión considerada es verdadera, en caso contrario es falsa. Por ejemplo, 8>4 (ocho mayor que cuatro) es verdadera, se representa por el valor true del tipo básico boolean, en cambio, 8<4 (ocho menor que cuatro) es falsa, false. En la primera columna de la tabla, se dan los símbolos de los operadores relacionales, el la segunda, el nombre de dichos operadores, y a continuación su significado mediante un ejemplo. Operador
nombre
ejemplo
significado
<
menor que
a
a es menor que b
>
mayor que
a>b
a es mayor que b
==
igual a
a==b
a es igual a b
!=
no igual a
a!=b
a no es igual a b
<=
menor que o igual a
a<=5
a es menor que o igual a b
>=
mayor que o igual a
a>=b
a es menor que o igual a b
Se debe tener especial cuidado en no confundir el operador asignación con el operador relacional igual a. Las asignaciones se realizan con el símbolo =, las comparaciones con ==.
En el programa RelacionApp, se compara la variable i que guarda un 8, con un conjunto de valores, el resultado de la comparación es verdadero (true), o falso (false). public class RelacionApp { public static void main(String[] args) { int x=8; int y=5; boolean compara=(xy); System.out.println("x>y es "+compara); compara=(x==y); System.out.println("x==y es "+compara); compara=(x!=y); System.out.println("x!=y es "+compara); compara=(x<=y); System.out.println("x<=y es "+compara); compara=(x>=y); System.out.println("x>=y es "+compara); } }
Los operadores lógicos Los operadores lógicos son: • • •
&& AND (el resultado es verdadero si ambas expresiones son verdaderas) || OR (el resultado es verdadero si alguna expresión es verdadera) ! NOT (el resultado invierte la condición de la expresión)
AND y OR trabajan con dos operandos y retornan un valor lógico basadas en las denominadas tablas de verdad. El operador NOT actúa sobre un operando. Estas tablas de verdad son conocidas y usadas en el contexto de la vida diaria, por ejemplo: "si hace sol Y tengo tiempo, iré a la playa", "si NO hace sol, me quedaré en casa", "si llueve O hace viento, iré al cine". Las tablas de verdad de los operadores AND, OR y NOT se muestran en las tablas siguientes El operador lógico AND x
y
resultado
tr u e
tr u e
tr u e
tr u e
false false
false true
false
false false false El operador lógico OR
x
y
resultado
tr u e
true
true
tr u e
false true
false true
true
false false false El operador lógico NOT x
resultado
tr u e
false
false true Los operadores AND y OR combinan expresiones relacionales cuyo resultado viene dado por la última columna de sus tablas de verdad. Por ejemplo: (a
es verdadero (true), si ambas son verdaderas. Si alguna o ambas son falsas el resultado es falso (false). En cambio, la expresión (a
es verdadera si una de las dos comparaciones lo es. Si ambas, son falsas, el resultado es falso. La expresión " NO a es menor que b" !(a
es falsa si (a=b)
La expresión "NO a es igual a b" !(a==b)
es verdadera si a es distinto de b, y es falsa si a es igual a b. Esta expresión es equivalente a (a!=b)
El flujo de un programa (sentencias condicionales) Introducción
La sentencia if La sentencia if...else La sentencia switch
Del mismo modo que en la vida diaria, en un programa es necesario tomar decisiones basadas en ciertos hechos h echos y actuar en consecuencia. cons ecuencia. El lenguaje Java Ja va tiene una sentencia básica denominada if (si condicional) que realiza un test y permite responder de acuerdo al resultado.
La sentencia if La sentencia if , actúa como cabría esperar. Si la condición es verdadera, la sentencia se ejecuta, de otro modo, se salta dicha sentencia, continuando la ejecución del programa con otras sentencias a continuación de ésta. La forma general de la sentencia if es: if (condición) sentencia;
Si el resultado del test es verdadero (true) se ejecuta la sentencia que sigue a continuación de if , en caso contrario, falso (false), se salta dicha sentencia, tal como se indica en la figura. La sentencia puede consistir a su vez, en un conjunto de sentencias agrupadas en un bloque. if (condición){ sentencia1; sentencia2; }
En el siguiente ejemplo, si el número del boleto que hemos adquirido coincide con el número aparecido en el sorteo, nos dicen que hemos obtenido un premio. if(numeroBoleto==numeroSorteo) System.out.println("has obtenido un premio");
La sentencia if...else La sentencia if...else completa la sentencia if , para realizar una acción alternativa if (condición) sentencia1; else sentencia2
Las dos primeras líneas indican que si la condición es verdadera se ejecuta la sentencia 1. La palabra clave else, significa que si la condición no es verdadera se ejecuta la sentencia 2, tal como se ve en la figura.. Dado que las sentencias pueden ser simples o compuestas la forma general de if...else es if (condición){ sentencia1; sentencia2; }else{
sentencia3 sentencia4; sentencia5; }
Existe una forma abreviada de escribir una sentencia condicional if...else como la siguiente: if (numeroBoleto==numeroSoreteo) premio=1000; else premio=0;
en una sola línea premio=(numeroBoleto==n premio=(numeroBoleto==numeroSoreteo umeroSoreteo) ) ? 1000 : 0;
Un ejemplo significativo es el siguiente: el signo de un número elevado a una potencia par es positivo, y es negativo ne gativo cuando está elevado elev ado a una potencia impar. i mpar. int signo=(exponente%2==0)? signo=(exponente%2==0)?1:-1; 1:-1;
La condición entre parántesis es la siguiente: un número es par, cuando el resto de la división entera de dicho número entre dos vale cero.
La sentencia switch switch1: SwitchApp1.java
switch2: SwitchApp2.java
Como podemos ver en la figura del apartado anterior, la sentencia if...else tiene dos ramas, el programa va por una u otra rama dependiendo del valor verdadero o falso de la expresión evaluada. A veces, es necesario, elegir entre varias alternativas, como se muestra en la siguiente figura
Por ejemplo, considérese las siguientes series de sentencias if...else if(expresion==valor1) sentencia1; else if(expresion==valor2) sentencia2; else if(expresion==valor3) sentencia3; else sentencia4;
El código resultante puede ser difícil de seguir y confuso incluso para el programador avanzado. El lenguaje Java proporciona una solución elegante a este problema mediante la sentencia condicional switch para agrupar a un conjunto de sentencias if...else. switch(expresion){ case valor1: sentencia1; break; case valor2: sentencia2; break; case valor3: sentencia3; break; default: sentencia4; }
//sale de switch
//sale switch
//sale de switch
En la sentencia switch, se compara el valor de una variable o el resultado de evaluar una expresión, con un conjunto de números enteros valor1, valor2, valor3, .. o con un conjunto de caracteres, cuando coinciden se ejecuta el bloque de sentencias que están asociadas con dicho número o carácter constante. Dicho bloque de sentencias no está entre llaves sino que empieza en la palabra reservada case y termina en su asociado break . Si el compilador no encuentra coincidencia, se ejecuta la sentencia default, si es que está presente en el código. Veamos ahora un ejemplo sencillo: dado el número que identifica al mes (del 1 al 12) imprimir el nombre del mes.
public class SwitchApp1 { public static void main(String[] args) { int mes=3; switch (mes) { case 1: System.out.println("Ener System.out.p rintln("Enero"); o"); break; case 2: System.out.println("Febr System.out.p rintln("Febrero"); ero"); break; case 3: System.out.println("Marz System.out.p rintln("Marzo"); o"); break; case 4: System.out.println("Abri System.out.p rintln("Abril"); l"); break; case 5: System.out.println("May System.out.println("Mayo"); o"); break; case 6: System.out.println("Juni System.out.p rintln("Junio"); o"); break; case 7: System.out.println("Juli System.out.p rintln("Julio"); o"); break; case 8: System.out.println("Ago System.out.println("Agosto"); sto"); break; case 9: System.out.println("Sep System.out.println("Septiembre"); tiembre"); break; case 10: System.out.println("Octubre"); break; case 11: System.out.println("Noviembre"); break; case 12: System.out.println("Diciembre"); break; default: System.out.println("Este System.out.println("Este mes no existe"); break; } } }
Ahora un ejemplo más complicado, escribir un programa que calcule el número de días de un mes determinado cuando se da el año. Anotar primero, los meses que tienen 31 días y los que tienen 30 días. El mes de Febrero (2º mes) es el más complicado ya que tiene 28 días excepto en los años que son bisiestos que tiene 29. 2 9. Son bisiestos los años múltiplos múltip los de cuatro, que no sean s ean múltiplos de 100, pero si son bisiestos los múltiplos de 400. public class SwitchApp2 { public static void main(String[] args) { int mes=2; int año=1992; int numDias=30; switch (mes) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: numDias = 31; break; case 4: case 6: case 9: case 11: numDias = 30; break; case 2: if ( ((año % 4 == 0) && !(año % 100 == 0)) || (año % 400 == 0) ) numDias = 29; else numDias = 28; break; default:
System.out.println("Este mes no existe"); break; } System.out.println("El mes "+mes+" del año "+año+" tiene "+numDias+" días"); } }
El flujo de un programa (sentencias iterativas) Introducción
La sentencia for La sentencia while La sentencia do...while La sentencia break La sentencia continue Ejemplo: los números primos
Tan importantes como las sentencias condiciones son las sentencias iterativas o repetitivas. Normalmente, las sentencias de un programa son ejecutadas en el orden en el que aparecen. Cada sentencia es ejecutada una y solamente una vez. El lenguaje Java, como la mayoría de los lenguajes, proporciona sentencias que permiten realizar una tarea una y otra vez hasta que se cumpla una determinada condición, dicha tarea viene definida por un conjunto de sentencias agrupadas en un bloque. Las sentencias iterativas son for, while y do...while
La sentencia for factorial: FactorialApp.java
Esta sentencia se encuentra en la mayoría de los lenguajes de programación. El bucle for se empleará cuando conocemos el número de veces que se ejecutará una sentencia o
un bloque de sentencias, tal como se indica en la figura. La forma general que adopta la sentencia for es for(inicialización; for(inicialización; condición; incremento) sentencia;
El primer término inicialización, se usa para inicializar una variable índice, que controla el número de veces que se ejecutará el bucle. La condición representa la condición que ha de ser satisfecha para que el bucle continúe su ejecución. El incremento representa la cantidad que se incrementa la variable índice en cada repetición. Ejemplo: Escribir un programa que imprima los primeros 10 primeros números enteros empezando por el cero for (int i = 0; i < 10; i++) { System.out.println(i); }
El resultado será: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 La variable índice i se declara y se inicializa en el término inicialización, la condición se expresa de modo que i se debe mantener estrictamente menor que 10; la variable i se incrementa una unidad en cada repetición del bucle. La variable i es local al bucle, por lo que deja de existir una vez que se sale del bucle. Ejemplo: Escribir un programa que imprima los números pares positivos menores o iguales que 20 for (int i=2; i <=20; i += 2) { System.out.println(i); }
Ejemplo: Escribir un programa que imprima los números pares positivos menores o iguales que 20 en orden decreciente for (int i=20; i >= 2; i -= 2) { System.out.println(i); }
Ejemplo: Escribir un programa que calcule el factorial de un número empleando la sentencia iterativa for. Guardar el resultado en un número entero de tipo long . Definición: el factorial de un número n es el resultado del producto 1*2*3* .... *(n-1)*n . public class FactorialApp { public static void main(String[] args) { int numero=4; long resultado=1; for(int i=1; i<=numero; i++){ resultado*=i; } System.out.println("El factorial es "+resultado); } }
La sentencia while factorial1: FactorialApp1.java
A la palabra reservada while le sigue una condición encerrada entre paréntesis. El bloque de sentencias sentencia s que le siguen se ejecuta ejecu ta siempre que la condición condició n sea verdadera tal como se ve en la figura. La forma general que adopta la sentencia while es: while (condición) sentencia;
Ejemplo: Escribir un programa que imprima los primeros 10 primeros números enteros empezando por el cero, empleando la sentencia iterativa while. int i=0; while (i<10) { System.out.println(i); i++; }
El valor inicial de i es cero, se comprueba la condición (i<10), la cual resulta verdadera. Dentro del bucle, se imprime i, y se incrementa la variable contador i, en una unidad. Cuando i vale 10, la condición (i<10) resulta falsa y el bucle ya no se ejecuta. Si el valor inicial de i fuese 10, no se ejecutaría el bucle. Por tanto, el bucle while no se ejecuta si la condición es falsa. Ejemplo: escribir un programa que calcule el factorial de un número empleando la sentencia iterativa while public class FactorialApp1 { public static void main(String[] args) { int numero=4; long resultado=1; while(numero>0){ resultado*=numero; numero--; } System.out.println("El factorial es "+resultado); } }
La sentencia do...while Como hemos podido apreciar las sentencias for y while la condición está al principio del bucle, sin embargo, do...while la condición está al final del bucle, por lo que el bucle se ejecuta por lo menos una vez tal como se ve en la figura. do marca el comienzo del bucle y while el final del mismo. La forma general es: do{ sentencia; }while(condición);
Ejemplo: Escribir un programa que imprima los primeros 10 primeros números enteros empezando por el cero, empleando la sentencia iterativa do..while.
int i=0; do{ System.out.println(i); i++; }while(i < 10);
El bucle do...while, se usa menos que el bucle while, ya que habitualmente evaluamos la expresión que controla el bucle al comienzo, no al final.
La sentencia break A veces es necesario interrumpir la ejecución de un bucle for, while, o do...while. for(int i = 0; i < 10; i++){ if (i == 8) break; System.out.println(i); }
Consideremos de nuevo el ejemplo del bucle for, que imprime los 10 primeros números enteros, se interrumpe la ejecución del bucle cuando se cumple la condición de que la variable contador i valga 8. El código se leerá: "salir del bucle cuando la variable contador i, sea igual a 8". Como podemos apreciar, la ejecución del bucle finaliza prematuramente. Quizás el lector pueda pensar que esto no es de gran utilidad pues, el código anterior es equivalente a for(int i = 0; i <=8; i++) System.out.println(i);
Sin embargo, podemos salir fuera del bucle prematuramente si se cumple alguna condición de finalización. while(true){ if (condicionFinal) //...otras sentencias }
break;
Como podemos apreciar en esta porción de código, la expresión en el bucle while es siempre verdadera, por tanto, tiene que haber algún mecanismo que nos permita salir del bucle. Si la condicion de finalización f inalización es verdadera, verdad era, es decir la variable condicionFinal del tipo boolean toma el valor true, se sale del bucle, en caso contrario se continua el procesmiento de los datos. dato s.
La sentencia continue
La sentencia continue, fuerza al bucle a comenzar la siguiente iteración desde el principio. En la siguiente porción de código, se imprimen imprime n todos los números del 0 al 9 excepto el número 8. for(int i = 0; i < 10; i++){ if (i == 8) continue; System.out.println(i); }
Etiquetas Tanto break como continue pueden tener una etiqueta opcional que indica a Java hacia donde dirigirse cuando se cumple una determinada condición. salida:
for(int i=0; i<20; i++){ while(j<70){ if(i*j==500) //... } //... }
break salida;
La etiqueta en este ejemplo se denomina salida, y se añade antes de la parte inicial del ciclo. La etiqueta debe terminar con el carácter dos puntos :. Si no disponemos de etiqueta, al cumplirse la condición i*j==500, se saldría del bucle interno while, pero el proceso de cálculo continuaría en el bucle externo for.
Ejemplo: los números primos primos: PrimosApp.java
Escribir un programa que calcule los números primos comprendidos entre 3 y 100. Los números primos tienen la siguiente característica: un número primo es solamente divisible por sí mismo y por la unidad, por tanto, un número primo no puede ser par excepto el 2. Para saber si un número impar es primo, dividimos dicho número por todos los números impares comprendidos entre 3 y la mitad de dicho número. Por ejemplo, para saber si 13 es un número primo basta dividirlo por 3, y 5. Para saber si 25 es número primo se divide entre 3, 5, 7, 9, y 11. Si el resto de la división (operación módulo %) es cero, el número no es primo. public class PrimosApp { public static void main(String[] args) { boolean bPrimo; System.out.println("Números primos comprendidos entre 3 y 100"); for(int numero=3; numero<100; numero+=2){
bPrimo=true; for(int i=3; i
En primer lugar, hacemos un bucle for para examinar los números impares comprendidos entre 3 y 100. Hacemos la suposición de que numero es primo, es decir, de que la variable de control bPrimo toma el valor true. Para confirmarlo, se halla el resto de la división entera entre numero, y los números i impares comprendidos entre 3 y numero/2. (Se recordará que todo número es divisible por la unidad). Si el número numero es divisible por algún número i (el resto de la división entera numero%i es cero), entonces el número numero no es primo, se abandona el bucle (break ) con la variable de control bPrimo tomando el valor false. En el caso de que numero sea un número primo, se completa el bucle interno, tomando la variable de control bPrimo el valor inicial true. Por último, si el número es primo, bPrimo es true, se imprime en la ventana, uno a continuación del otro separados por un guión. En este programa podemos observar la diferencia entre print y println. El sufijo ln en la segunda función indica que se imprime el argumento y a continuación se pasa a la línea siguiente.
Ventajas y desventajas 1) Ventajas a) Aumento de la productividad productividad:: Los usuarios pueden utilizar herramientas que le son familiares, como hojas de cálculo y cálculo y herramientas de acceso a bases de datos. Mediante la integración de las aplicaciones cliente / servidor con las aplicaciones personales de uso habitual, los usuarios pueden construir soluciones particularizadas que se ajusten a sus necesidades cambiantes. Una interface gráfica de usuario consistente, reduce el tiempo de aprendizaje de las aplicaciones. b) Menores costos de operación: La existencia de plataformas de hardware cada vez más baratas. Esta constituye a su vez una de las más palpables ventajas de este esquema, la posibilidad de utilizar máquinas considerablemente más baratas que las requeridas por una solución centralizada, basada en sistemas grandes.
•
•
•
•
Permiten un mejor aprovechamiento de los sistemas existentes, protegiendo la inversión inversión.. Por ejemplo, la compartición de servidores (habitualmente caros) y dispositivos y dispositivos periféricos (como impresoras impresoras)) entre máquinas clientes, permite un mejor rendimiento del conjunto. Se pueden utilizar componentes, tanto de hardware como de software, de varios fabricantes, lo cual contribuye contribuye considerablemente a la reducción de costos y favorece la flexibilidad en la implantación y actualización de soluciones. Proporcionan un mejor acceso a los datos. La interface de usuario ofrece una forma homogénea de ver el sistema, independientemente de los cambios o actualizaciones que se produzcan en él y de la ubicación de la información. El movimiento de funciones desde un ordenador central hacia servidores o clientes locales, origina el desplazamiento de los costos de ese proceso hacia máquinas más pequeñas y por tanto, más baratas.
c) Mejora en el rendimiento de la red: Las arquitecturas cliente/servidor eliminan la necesidad de mover grandes bloques de información por la red hacia los ordenadores personales o estaciones de trabajo para su proceso. Los servidores controlan los datos, procesan peticiones y después transfieren sólo los datos requeridos a la máquina cliente. Entonces, la máquina cliente presenta los datos d atos al usuario mediante interfaces amigables. Todo esto reduce el tráfico de la red, lo que facilita que pueda soportar un mayor número de usuarios. Se puede integrar PCs con sistemas medianos y grandes, sin que todas las máquinas tengan que utilizar el mismo sistema operacional. Si se utilizan interfaces gráficas para interactuar con el usuario, el esquema Cliente/Servidor presenta la ventaja, con respecto a uno centralizado, de que no es siempre necesario transmitir información gráfica por la red, pues ésta puede residir en el cliente, lo cual permite aprovechar mejor el ancho de banda de la red. Tanto el cliente como el servidor pueden escalar para ajustarse a las necesidades de las aplicaciones. Las UCPs utilizadas en los respectivos equipos, pueden dimensionarse a partir de las aplicaciones y el tiempo de respuesta que se requiera. La existencia de varias UCPs proporciona una red más fiable: una falla en uno de los equipos, no significa necesariamente que el sistema deje de funcionar. En una arquitectura como ésta, los clientes y los servidores son independientes los unos de los otros, con lo que pueden renovarse para aumentar sus funciones y capacidad de forma independiente, sin afectar afectar al resto del sistema. La arquitectura modular de los sistemas cliente / servidor, permite el uso de ordenadores especializados (servidores de base de datos, servidores de ficheros, estaciones de trabajo para CAD, etc.). Permite centralizar el control de sistemas que estaban descentralizados, como por ejemplo la gestión de los ordenadores personales que antes estuvieron aislados.
Es más rápido el mantenimiento mantenimiento y y el desarrollo de aplicaciones, pues se pueden emplear las herramientas existentes (por ejemplo los servidores de SQL o las herramientas de más bajo nivel como los sockets o el RPC ). El esquema Cliente/Servidor contribuye además a proporcionar a las diferentes direcciones de una institución soluciones locales, pero permitiendo además la integración de la información relevante a nivel global.
2) Desventajas Hay una alta complejidad tecnológica al tener que integrar una gran variedad de productos. Por una parte, el mantenimiento de los sistemas es más difícil pues implica la interacción de diferentes partes de hardware y de software, distribuidas por distintos proveedores, lo cual dificulta el diagnóstico de fallas. Requiere un fuerte rediseño de todos los elementos involucrados en los sistemas de información (modelos de datos, procesos, interfaces, comunicaciones, almacenamiento de datos, etc.). Además, en la actualidad existen pocas herramientas que ayuden a determinar la mejor forma de dividir las aplicaciones entre la parte cliente y la parte servidor. Por un lado, es importante que los clientes y los servidores utilicen el mismo mecanismo (por ejemplo sockets o RPC), lo cual implica que se deben tener mecanismos generales que existan en diferentes plataformas. Además de lo anterior, se cuenta con muy escasas herramientas herramientas para la administración y ajuste del desempeño de los sistemas. Es más difícil asegurar un elevado grado de seguridad en una red de clientes y servidores que en un sistema con un único ordenador centralizado. Se deben hacer verificaciones en el cliente y en el servidor. También se puede recurrir a otras técnicas como el encriptamiento. Un aspecto directamente relacionado con el anterior, es el de cómo distribuir los datos en la red. En el caso de una empresa, empresa, por ejemplo, éste puede ser hecho por departamentos, geográficamente, o de otras maneras. Además, hay que tener en cuenta que en algunos casos, por razones de confiabilidad o eficiencia se pueden tener datos replicados, y que puede haber actualizaciones simultáneas. A veces, los problemas de congestión de la red pueden degradar el rendimiento del sistema por debajo de lo que se obtendría con una única máquina (arquitectura centralizada). También la interface gráfica de usuario puede a veces ralentizar el funcionamiento funcionamiento de la aplicación. El quinto nivel de esta arquitectura (bases de datos distribuidas) es técnicamente muy complejo y en la actualidad, hay muy pocas implantaciones que garanticen un funcionamiento totalmente eficiente. Existen multitud de costos ocultos (formación en nuevas tecnologías, licencias, cambios organizativos, etc.) que encarecen su implantación.