Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
PREFACIO
Cuando hace dos cursos el profesor Francisco José García Peñalvo nos propuso redactar
el esbozo de un tutorial sobre Java, de carácter voluntario, y aunque los alumnos
siempre somos reacios a una carga de trabajo sin compensación en la calificación,
sorprendentemente, los alumnos aceptamos. La continua apuesta de "Fran" por su
alumnado, y la confianza que en nosotros depositó, realmente nos estimuló a dar todo lo
mejor de nosotros.
Aunque desgraciadamente aquel año no toda la clase pudiera superar la asignatura,
sobre todo por la carga docente, pocas voces he oído en desacuerdo con las novedosas
formas docentes que aquel año se experimentaron.
Aunque la redacción de la primera versión, hecha por diferentes grupos de trabajo, era
muy vaga, heterogénea y estaba llena de erratas, ha sido el pilar de este tutorial, tanto
como esquema de temas a tratar, como bibliografía a manejar.
En la redacción de este tutorial se ha pretendido abarcar el mayor número de aspectos
posibles de la gran variedad de temas que rodean a Java. Espero no haber perdido nunca
de vista que este tutorial debe de servir tanto a expertos informáticos como a
programadores de cualquier tipo que, aun no teniendo idea de programación orientada a
objetos, tengan interés en Java.
Así mismo espero que la bibliografía aportada sea suficiente para aquellos que hayáis
quedado prendados de la potencia de este nuevo lenguaje de programación.
Debo decir que mientras desarrollaba este tutorial me ha impresionado la potencia de
Java por tres motivos principales:
• Sus amplias bibliotecas multiplataforma.
• La posibilidad de desarrollar aplicaciones que funcionen en Internet mediante
navegadores (applets).
• Todo ello con un lenguaje orientado a objeto sencillo pero potente.
Esperemos que pronto los problemas de incompatibilidad entre Microsoft Explorer y
Netscape Navigator se solucionen, con lo que se vivirá un futuro lleno de esplendor para
Java.
Contenidos
Este tutorial ha sido dividido en una serie de temas (cada uno de ellos compuesto de
varios apartados) para una más fácil consulta y una mayor claridad en cuánto a qué se
está intentando explicar.
A continuación se detalla de una forma general los contenidos de cada uno de los
apartados.
En el primer tema "I. Introducción" se intenta acercar al lector el mundo Java desde una
perspectiva global; su historia, sus características principales y una comparativa con
otros lenguajes orientados a objeto, para que el lector pueda juzgar si le interesa
aprender Java y para que vaya vislumbrando en qué puntos le va a interesar profundizar.
En un primer apartado se introducen todos los conceptos necesarios para poder entender
un lenguaje de programación orientado a objeto, como es Java. Este apartado debe ser
de especial interés para todos aquellos lectores que no hayan desarrollado jamás
programas en un lenguaje orientado a objeto, y debe facilitar la comprensión de muchos
conceptos básicos para un mejor entendimiento del resto del tutorial.
El segundo tema "II. Lenguaje" define todos los conceptos básicos y sintaxis del
lenguaje Java; las estructuras que utiliza, su sintaxis, sus sistemas de control...
Los cuatro primeros apartados de este tema son fundamentales para comprender
cualquier fragmento de código Java, y aunque sencillos son similares a los de cualquier
otro lenguaje de programación.
Los temas cinco, seis y siete introducen los aspectos orientados a objeto del lenguaje
Java, comenzando desde los más sencillos como son los objetos y las clases hasta los
más complejos como pueden ser la herencia y el polimorfismo.
Entre los apartados ocho y once se comentan diversos aspectos propios del lenguaje
Java, que dotan a los programas de una mayor potencia como son las excepciones, los
threads, las interfaces y los paquetes.
Por último en el apartado doce se explican los fundamentos sobre la construcción de
programas Java, aplicaciones que se pueden construir y diversos aspectos referentes a
ellas.
El tercer tema "III. Bibliotecas de la API de Java" trata, de una forma global, todas las
bibliotecas de la API de Java que servirán para dotar a los programas de una gran
potencia con multitud de clases e interfaces estándar ya programadas y distribuidas por
Sun.
Además, en un par de apartados se explican las gestiones de las cadenas y de los flujos
de entrada/salida que hace Java. Estas acciones se realizan de forma sensiblemente
diferente a la de otros lenguajes de programación, como por ejemplo C o C++.
En el cuarto tema "IV. Bibliotecas gráficas", se explican las dos bibliotecas que Java
incorpora para desarrollar interfaces gráficas de usuario: AWT y la nueva Swing.
En el quinto tema "V. Java e Internet", se explica la potencia de Java para el desarrollo
de aplicaciones en red, así como el paquete java.net, el cual da soporte a un montón de
operaciones para el diálogo de diversas aplicaciones de red con aspectos como los
sockets.
En el sexto tema "VI. Applets" se explica el fundamento de este tipo de aplicaciones
especialmente diseñadas para su uso en Internet. Son características de Java y le aportan
una potencia inusitada para el desarrollo de aplicaciones para Internet. Además en este
tema se acompañan una serie de ejemplos para intentar aclarar el desarrollo y
funcionamiento de este tipo de aplicaciones.
Por último al tutorial se le adjuntan una serie de apéndices que sirvan como breves
reseñas sobre diferentes aspectos de Java que por una u otra cuestión se ha decidido que
vayan aparte de lo que es el bloque del lenguaje.
Así en el primer apéndice "Apéndice I: JDK", se explica en detalle el funcionamiento
del JDK, herramienta que distribuye Sun para el desarrollo de aplicaciones Java.
En el segundo apéndice "Apéndice II: Herramientas de desarrollo", se comentan las
diferentes herramientas disponibles en el mercado para desarrollar aplicaciones Java,
depurarlas y probarlas.
En un tercer apéndice "Apéndice III: Métodos Nativos" se explica mediante un ejemplo
de cómo Java es capaz de utilizar código de aplicaciones escritas en otros lenguajes de
programación.
En el cuarto apéndice "Apéndice IV: Guía de referencia de Java a C++" se explican las
similitudes y diferencias entre estos dos lenguajes de programación, dado que Java es un
lenguaje derivado de C++, pero con notables diferencias respecto a su predecesor. Este
apéndice puede ser fundamental para aquellos programadores que proviniendo de C++
quieran conocer el lenguaje Java, ya que su similitud sintáctica es, en muchos casos,
engañosa.
En el último apéndice "Apéndice V: Guía de referencia del lenguaje", se explican, a
modo de resumen, las características fundamentales del lenguaje Java
Agradecimientos
Me gustaría aprovechar este momento para felicitar a Francisco José García Peñalvo por
el esfuerzo que hace por una docencia más moderna y atractiva, así como la confianza
que deposita en su alumnado, y por el agradable clima de trabajo que ha creado para la
realización de este tutorial.
Así mismo me gustaría agradecer al Área de Lenguajes y Sistemas Informáticos de la
Universidad de Burgos la confianza depositada en mi así como toda la documentación
bibliográfica que me han facilitado.
Por último me gustaría agradecer muy especialmente a Amelia Pajares Rojo su
colaboración espontánea en este proyecto, consiguiendo así un tutorial mucho más claro
y legible.
Espero que este tutorial realmente os agrade a todos.
Ignacio Cruzado Nuño
Burgos, Septiembre de 1999
PRÓLOGO
Prólogo de la primera versión de la guía de Java
Java es actualmente uno de esos términos mágicos que revolucionan las tecnologías de
la información cada cierto tiempo. Java es un lenguaje de programación orientado a
objetos creado por la compañía Sun Microsystems, que desde su aparición en 1995 ha
provocado una autentica conmoción en los entornos informáticos. El éxito del lenguaje
Java viene de la mano de la filosofía y la forma de operación de las aplicaciones escritas
en Java, todo ello estrechamente ligado a Internet y al WWW.
El hecho de que el lenguaje Java sea un lenguaje joven en evolución no le ha permitido
entrar a formar parte habitualmente de los currículum universitarios, poco dados a
admitir innovaciones con tanta celeridad. Sin embargo, Java comienza a entrar en las
Universidades Españolas, especialmente de la mano de los proyectos de final de carrera
en las titulaciones de informática.
Aprovechando la convocatoria de 1998 de la Consejería de Educación y Cultura de la
Junta de Castilla y León para la concesión de ayudas para la elaboración de Recursos de
Apoyo a la Enseñanza Universitaria en esta Comunidad Autonómica, se decidió realizar
una actividad que tuviera como protagonista al lenguaje Java, a la vez que se exploraba
una nueva forma de involucrar de una manera más activa al alumnado en las actividades
docentes, así como de incentivar al profesorado en aras de conseguir una docencia de
mayor calidad.
La actividad que se propuso llevar a cabo fue una Guía Hipermedia para el Aprendizaje
del Lenguaje java.
Con la realización de esta guía se perseguían una serie de objetivos tanto docentes como
pragmáticos. Los objetivos docentes estaban centrados en la búsqueda de la mejora de la
calidad docente, reflejada en una mayor participación de los alumnos y en una mejora
de la relación profesor-alumno. Los objetivos pragmáticos se centraban en el
acercamiento del lenguaje Java al curriculum de los alumnos matriculados en la
asignatura "Programación Avanzada" correspondiente al tercer curso de la titulación
"Ingeniería Técnica en Informática de Gestión en la Universidad de Burgos".
A continuación se recogen tanto los objetivos docentes como los objetivos pragmáticos
propuestos.
Objetivos Docentes:
• Establecer una nueva forma de participación activa de los alumnos en el
desarrollo de su currículum universitario, en contraposición de la actitud pasiva
que tradicionalmente asume el alumno en las clases.
• Dotar a alumnos y profesores de las responsabilidades que conlleva la
realización de una actividad en grupo.
• Completar los contenidos del curriculum universitario del alumno con temas
novedosos que no suelen tener cabida en el programa de las asignaturas.
• Aumentar la cantidad y la calidad de la relación profesor-alumno.
Objetivos Pragmáticos:
• Introducir el lenguaje Java dentro de la titulación Ingeniería Técnica en
Informática de Gestión de la Universidad de Burgos.
• Elaborar una guía de referencia hipermedia del lenguaje Java accesible vía
Internet y distribuíble en CD-ROM. Esta guía podrá ser utilizada tanto para el
autoaprendizaje, como para material docente o como material de consulta en los
proyectos de final de carrera.
• Aprender de la experiencia para repetir esta técnica en otras asignaturas de la
titulación e incluso en otras Universidades.
Este proyecto se va a acometer en dos fases bien diferenciadas:
Una primera fase (Enero 1998 – Diciembre 1998) donde se planifica todo el proyecto y
se obtiene una primera guía básica de referencia básica (producto que viene
representado por la presente guía).
Una segunda fase (Enero 1999 – Diciembre 1999) donde se amplía la primera guía
introductoria con los conceptos más avanzados del lenguaje y se enriquece de los
comentarios recibidos sobre la primera guía.
Para la realización práctica de esta primera guía se ha utilizado exclusivamente HTML
(Hyper Text Markup Language), debido a que sus características hipermedia lo hacen
idóneo para el desarrollo de este tipo de productos.
La metodología empleada para la creación de esta guía ha consistido en formar grupos
de trabajo formados por tres alumnos cada uno (los alumnos que formaban cada uno de
los grupos eran alumnos de la asignatura Programación Avanzada del tercer curso de
la Ingeniería Técnica en Informática de Gestión de la Universidad de Burgos, que
voluntariamente se ofrecieron para colaborar en esta iniciativa). Cada grupo se
encargaba de elaborar una serie de temas que en su conjunto dan forma a la presente
guía, siendo su trabajo coordinado por alguno de los profesores colaboradores. Una vez
que los temas estaban terminados eran revisados e integrados en la guía por el
coordinador técnico del proyecto.
Burgos, 5 de Octubre de 1998
Miguel Ángel Manzanedo del Campo
Francisco José García Peñalvo
Prólogo de la segunda versión de la guía de Java
En los casi dos años en los que se ha venido desarrollando esta guía introductoria al
lenguaje Java, hemos asistido al afianzamiento de Java como plataforma de desarrollo y
a una constante evolución que, aunque todavía lejos de una madurez plena, ha abierto
numerosos campos de aplicación para esta plataforma (acceso a bases de datos,
interacción con CORBA, aplicaciones distribuidas...).
Durante este tiempo han proliferado multitud de referencias en torno al fenómeno Java
(en forma de libros, artículos, tutoriales...), sin embargo, la guía que hemos realizado no
pretende sustituir a ninguno de ellos, sino más bien completarlos presentando una forma
sencilla y directa de introducirse al lenguaje Java y ofreciendo un acceso sencillo
basado en la facilidad de navegación hipermedia que aporta HTML.
A parte de la guía realizada, como producto final resultado del proyecto financiado por
la Consejería de Educación y Cultura de la Junta de Castilla y León en su convocatoria
de ayudas de 1998, este proyecto ha aportado unas experiencias especialmente
interesantes al verse satisfechos los objetivos docentes y pragmáticos que se buscaban al
iniciar este trabajo, y que se indicaban en el prólogo a la primera versión de esta guía
que aquí se presenta.
Si personalmente, tuviera que destacar una sola cosa de esta experiencia, no dudaría en
destacar el valor humano logrado al potenciar la relación profesor-alumno (hoy en día
ex-alumnos) y entre compañeros de diferentes Universidades de Castilla y León para
lograr el fin extra académico propuesto.
También me gustaría destacar el hecho constatado de que la elaboración de esta guía a
contribuido en gran manera a la introducción del lenguaje Java dentro de la titulación de
Ingeniería Técnica en Informática de Gestión de la Universidad de Burgos, y está
haciendo lo propio en la Ingeniería Técnica en Informática de Sistemas de la
Universidad de Salamanca.
En el ámbito técnico destacar la revisión realizada de los contenidos de la primera
versión de la guía, así como la ampliación en temas relacionados con la programación
cliente/servidor en Internet, los entornos gráficos de usuario o la incorporación de
métodos nativos entre otros interesantes temas, que dan un enorme valor a esta guía
como fuente de referencia práctica.
No quisiera terminar este prólogo sin antes tener unas palabras de agradecimiento y
recuerdo para todos aquéllos que participaron de una u otra manera en la elaboración de
esta guía, especialmente para mis ex-compañeros del Área de Lenguajes y Sistemas
Informáticos de la Universidad de Burgos, para todos mis antiguos alumnos que se
dejaron "engañar" para iniciar esta aventura y para Ignacio Cruzado cuyo trabajo en
estos últimos meses ha dotado de contenido y forma a la versión de la guía que hoy se
hace realidad.
Salamanca, 13 de octubre de 1999
Francisco José García Peñalvo
Sencillez Sí Sí No
Robustez Sí Sí No
Seguridad Sí Algo No
Interpretado Sí Sí No
Dinamicidad Sí Sí No
Portabilidad Sí Algo No
Neutralidad Sí Algo No
Threads Sí No No
Garbage Colection Sí Sí No
Excepciones Sí Sí Algunas
II.1. FUNDAMENTOS
A. Introducción
Java es un lenguaje orientado a objetos, que se deriva en alto grado de C++, de tal forma
que puede ser considerado como un C++ nuevo y modernizado o bien como un C++ al
que se le han amputado elementos heredados del lenguaje estructurado C.
B. Tokens
Un token es el elemento más pequeño de un programa que es significativo para el
compilador. Estos tokens definen la estructura de Java.
Cuando se compila un programa Java, el compilador analiza el texto, reconoce y
elimina los espacios en blanco y comentarios y extrae tokens individuales. Los tokens
resultantes se compilan, traduciéndolos a código de byte Java, que es independiente del
sistema e interpretable dentro de un entorno Java.
Los códigos de byte se ajustan al sistema de máquina virtual Java, que abstrae las
diferencias entre procesadores a un procesador virtual único.
Los tokens Java pueden subdividirse en cinco categorías: Identificadores, palabras
clave, constantes, operadores y separadores.
a.) Identificadores
Los identificadores son tokens que representan nombres asignables a variables, métodos
y clases para identificarlos de forma única ante el compilador y darles nombres con
sentido para el programador.
Todos los identificadores de Java diferencian entre mayúsculas y minúsculas (Java es
Case Sensitive o Sensible a mayúsculas) y deben comenzar con una letra, un
subrayado(_) o símbolo de dólar($). Los caracteres posteriores del identificador pueden
incluir las cifras del 0 al 9. Como nombres de identificadores no se pueden usar palabras
claves de Java.
Además de las restricciones mencionadas existen propuestas de estilo. Es una práctica
estándar de Java denominar:
• Las clases: Clase o MiClase.
• Las interfaces: Interfaz o MiInterfaz.
• Los métodos: metodo() o metodoLargo().
• Las variables: altura o alturaMedia.
• Las constantes: CONSTATE o CONSTANTE_LARGA.
• Los paquetes: java.paquete.subpaquete.
Sin entrar en más detalle en la siguiente línea de código se puede apreciar la declaración
de una variable entera (int) con su correspondiente identificador:
int alturaMedia;
b.) Palabras clave
Las palabras claves son aquellos identificadores reservados por Java para un objetivo
determinado y se usan sólo de la forma limitada y específica. Java tiene un conjunto de
palabras clave más rico que C o que C++, por lo que sí está aprendiendo Java con
conocimientos de C o C++, asegúrese de que presta atención a las palabras clave de
Java.
Las siguientes palabras son palabras reservadas de Java:
+ ^ <= ++ %=
>>>= - ~ >= -
== <<= [ / ||
>> += ^= ] %
! >>> = != (
& < *= ) |
Se ignoran todos los caracteres detrás de // hasta el fin de línea. Proviene del
//comentario
C++
// Bloque externo
int x = 1;
int y = 2;
Tipo Tamaño
Tipo Tamaño
Continuación \ \
Retroceso \b \u0008
float double
II.3. OPERADORES
A. Introducción
Los operadores son un tipo de tokens que indican una evaluación o computación para
ser realizada en objetos o datos, y en definitiva sobre identificadores o constantes.
Además de realizar la operación, un operador devuelve un valor, ya que son parte
fundamental de las expresiones.
El valor y tipo que devuelve depende del operador y del tipo de sus operandos. Por
ejemplo, los operadores aritméticos devuelven un número como resultado de su
operación.
Los operadores realizan alguna función sobre uno, dos o tres operandos.
Los operadores que requieren un operando son llamados operadores unarios. Por
ejemplo, el operador "++" es un operador unario que incrementa el valor de su
operando en una unidad.
Los operadores unarios en Java pueden utilizar tanto la notación prefija como la posfija.
La notación prefija indica que el operador aparece antes que su operando.
++contador // Notación prefija, se evalúa a: contador+1
La notación posfija indica que el operador aparece después de su operando:
contador++ // Notación posfija, se evalúa a: contador
Los operadores que requieren dos operandos se llaman operadores binarios. Por
ejemplo el operador "=" es un operador binario que asigna el valor del operando del
lado derecho al operando del lado izquierdo.
Todas los operadores binarios en Java utilizan notación infija, lo cual indica que el
operador aparece entre sus operandos.
operando1 operador operando2
Por último, los operadores ternarios son aquellos que requieren tres operandos. El
lenguaje Java tiene el operador ternario, "?":, que es una sentencia similar a la if-else.
Este operador ternario usa notación infija; y cada parte del operador aparece entre
operandos:
expresión ? operación1 : operación2
Los operadores de Java se pueden dividir en las siguientes cuatro categorías:
• Aritméticos.
• De comparación y condicionales.
• A nivel de bits y lógicos.
• De asignación.
B. Operadores aritméticos
El lenguaje Java soporta varios operadores aritméticos para los números enteros y en
coma flotante. Se incluye + (suma), - (resta), * (multiplicación), / (división), y %
(módulo, es decir, resto de una división entera). Por ejemplo:
sumaEste + aEste; //Suma los dos enteros
divideEste % entreEste; //Calcula el resto de dividir 2
enteros
& op1 & op2 op1 y op2 son ambos verdaderos, siempre evalúa op1 y op2
| op1 | op2 op1 o op2 son verdaderos, siempre evalúa op1 y op2
! ! op op es falso
>> op1 >> op2 Desplaza los bits de op1 a la derecha op2 veces
<< op1 << op2 Desplaza los bits de op1 a la izquierda op2 veces
~ ~op2 Complemento
El operador | realiza la operación OR de bit. Aplica la función OR sobre cada par de bits
de igual peso de cada operando. La función OR es evaluada a cierto si alguno de los
operandos es cierto.
El operador ^ realiza la operación OR exclusivo de bit (XOR). Aplica la función XOR
sobre cada par de bits de igual peso de cada operando. La función XOR es evaluada a
cierto si los operandos tienen el mismo valor.
Para finalizar, el operador de complemento invierte el valor de cada bit del operando.
Convierte el falso en cierto, y el cierto en falso:
Entre otras cosas, la manipulación bit es útil para gestionar indicadores booleanos
(banderas). Supongamos, por ejemplo, que se tiene varios indicadores booleanos en
nuestro programa, los cuales muestran el estado de varios componentes del programa:
esVisible, esArrastrable, etc... En lugar de definir una variable booleana para cada
indicador, se puede definir una única variable para todos ellos. Cada bit de dicha
variable representará el estado vigente de uno de los indicadores. Se deberán utilizar
entonces manipulaciones de bit para establecer y leer cada indicador.
Primero, se deben preparar las constantes de cada indicador. Esos indicadores deben ser
diferentes unos de otros (en sus bits) para asegurar que el bit de activación no se solape
con otro indicador. Después se debe definir la variable de banderas, cuyos bits deben de
poder ser configurados según el estado vigente en cada indicador.
El siguiente ejemplo inicia la variable de banderas flags a 0, lo que significa que todos
los indicadores están desactivados (ninguno de los bits es 1):
final int VISIBLE = 1;
final int ARRASTRABLE = 2;
final int SELECCIONABLE = 4;
final int MODIFICABLE = 8;
int flags = 0;
Para activar el indicador VISIBLE, se deberá usar la sentencia:
flags = flags | VISIBLE;
Para comprobar la visibilidad se deberá usar la sentencia:
if ( (flags & VISIBLE) == 1 )
E. Operadores de asignación
El operador de asignación básico es el =, que se utiliza para asignar un valor a otro. Por
ejemplo:
int contador = 0;
Inicia la variable contador con un valor 0.
Java además proporciona varios operadores de asignación que permiten realizar un atajo
en la escritura de código. Permiten realizar operaciones aritméticas, lógicas, de bit y de
asignación con un único operador.
Supongamos que necesitamos sumar un número a una variable y almacenar el resultado
en la misma variable, como a continuación:
i = i + 2;
Se puede abreviar esta sentencia con el operador de atajo +=, de la siguiente manera:
i += 2;
La siguiente tabla muestra los operadores de atajo de asignación y sus equivalentes
largos:
Multiplicación */%
Suma +-
Desplazamiento <<
Igualdad == !=
OR a nivel de bit ^
OR lógico ||
Condicional ?:
in.read();
Donde bastaría cambiar el 3 por cualquier otro número para que la lectura se repitiese
ese número de veces.
El lenguaje Java soporta las estructuras de control:
Sentencia Clave
if ( condición )
else
La parte del else es opcional, y un bloque de código puede ser simplemente la sentencia
vacía ; para representar que en ese caso no se ha de ejecutar nada.
Supongamos que un programa debe realizar diferentes acciones dependiendo de si el
usuario oprime el botón aceptar o el botón cancelar en una ventana de dialogo. Nuestro
programa puede realizar esto usando la sentencia if - else:
if (respuesta == Aceptar) {
else {
}
Se pueden anidar expresiones if-else, para poder implementar aquellos casos con
múltiples acciones. Esto es lo que se suele denominar como sentencias else if.
Por ejemplo, supongamos que se desea escribir un programa que clasifique según el
contenido de una variable valor, asigne una letra a una variable clasificacion: A para un
valor del 100-91, B de 90-81, C para 80-71 y F si no es ninguno de los anteriores:
int valor;
char clasificacion;
{clasificacion='A';}
else
{clasificacion='B';}
else
{clasificacion='C';}
else
{clasificacion='F';}
Se pueden escribir los if en las mismas líneas que los else, pero desde este tutorial se
insta a utilizar la forma indentada (como se ha podido ver en el ejemplo), pues es más
clara para el lector.
Este sistema de programación (else if) no es demasiado recomendable, y por ello el
lenguaje Java incluye la sentencia switch, que veremos a continuación, para dirigir el
flujo de control de variables con múltiples valores.
b.) La sentencia switch
Mediante la sentencia switch se puede seleccionar entre varias sentencias según el valor
de cierta expresión.
La forma general de switch es la siguiente:
switch ( expresionMultivalor ) {
switch ( meses ){
//Demas meses
// . . .
case 12: System.out.println( "Diciembre" ); break;
Por supuesto, se puede implementar esta estructura como una sentencia if else if:
int meses;
if ( meses == 1 ) {
System.out.println( "Enero" );
else
if ( meses == 2 ) {
System.out.println( "Febrero" );
El decidir si usar la sentencia if o switch depende del criterio de cada caso. Se puede
decidir cuál usar basándonos en la legibilidad, aunque se recomienda utilizar switch
para sentencias con más de tres o cuatro posibilidades.
C. Sentencias de iteración o bucles: for, do, while
a.) Bucle while
El bucle while es el bucle básico de iteración. Sirve para realizar una acción
sucesivamente mientras se cumpla una determinada condición.
La forma general del bucle while es la siguiente:
while ( expresiónBooleana ) {
sentencias;
};
i = i * 2;
Con él se podrían eliminar los bucles do-while y for por ser extensiones de éste, pero
que se incluyen en el lenguaje para facilitar la programación.
b.) Bucle do-while
El bucle do-while es similar al bucle while, pero en el bucle while la expresión se evalúa
al principio del bucle y en el bucle do-while la evaluación se realiza al final.
La forma general del bucle do-while es la siguiente:
do {
sentencias;
} while ( expresiónBooleana );
int c;
do {
c = System.in.read( );
sentencias;
La iniciación es una sentencia que se ejecuta una vez antes de entrar en el bucle.
La terminación es una expresión que determina cuándo se debe terminar el bucle. Esta
expresión se evalúa al final de cada iteración del bucle. Cuando la expresión se evalúa a
falso, el bucle termina.
El incremento es una expresión que es invocada en cada iteración del bucle. En realidad
puede ser una acción cualquiera, aunque se suele utilizar para incrementar una variable
contador:
for ( i = 0 ; i < 10 ; i++ )
Algunos (o todos) estos componentes pueden omitirse, pero los puntos y coma siempre
deben aparecer (aunque sea sin nada entre sí).
Se debe utilizar el bucle for cuando se conozcan las restricciones del bucle (su
instrucción de iniciación, criterio de terminación e instrucción de incremento).
Por ejemplo, los bucles for son utilizados comúnmente para iterar sobre los elementos
de una matriz, o los caracteres de una cadena:
// cad es una cadena (String)
System.out.print(" i="+i);
if ( j==5 )
System.out.print(" j="+j);
Al interpretar break a, no solo se rompe la ejecución del bucle interior (el de j), sino que
se salta al final del bucle i, obteniéndose:
i=1 j=1 j=2 j=3
Nota: Se desaconseja esta forma de programación, basada en goto, y con saltos de flujo
no controlados.
b.) Sentencia continue
Del mismo modo que en un bucle se puede desear romper la iteración, también se puede
desear continuar con el bucle, pero dejando pasar una determinada iteración.
Se puede usar la sentencia continue dentro de los bucles para saltar a otra sentencia,
aunque no puede ser llamada fuera de un bucle.
Tras la invocación a una sentencia continue se transfiere el control a la condición de
terminación del bucle, que vuelve a ser evaluada en ese momento, y el bucle continúa o
no dependiendo del resultado de la evaluación. En los bucles for además en ese
momento se ejecuta la cláusula de incremento (antes de la evaluación). Por ejemplo el
siguiente fragmento de código imprime los números del 0 al 9 no divisibles por 3:
if ( ( i % 3 ) == 0 )
continue;
Del mismo modo que break, en las sentencias continue se puede indicar una etiqueta de
bloque al que hace referencia. Con ello podemos referirnos a un bloque superior, si
estamos en bucles anidados. Si dicha etiqueta no es indicada, se presupone que nos
referimos al bucle en el que la sentencia continue aparece.
Por ejemplo, el siguiente fragmento de código:
void gotoContinue( ) {
if ( j>i ) {
System.out.println(" ");
continue f;
}
}
boolean condicion;
int devuelveContadorIncrementado(){
return ++contador;
void metodoReturn(){
//Sentencias
if ( condicion == true )
return;
E. Excepciones
Las excepciones son otra forma más avanzada de controlar el flujo de un programa. Con
ellas se podrán realizar acciones especiales si se dan determinadas condiciones, justo en
el momento en que esas condiciones se den.
Estudiaremos más este sistema de control en el capítulo "II.8. Gestión de excepciones y
errores" de este tutorial.
int x, y;
void metodoVacio( ) { }
x = paramX;
y = paramY;
MiPunto() {
tipo_de_variable nombre_de_atributo1;
tipo_de_variable nombre_de_atributo2;
// . . .
cuerpo_del_método1;
}
tipo_devuelto nombre_de_método2( lista_de_parámetros ) {
cuerpo_del_método2;
// . . .
Los tipos tipo_de_variable y tipo_devuelto, han de ser tipos simples Java o nombres de
otras clases ya definidas. Tanto Nombre_De_Clase, como los nombre_de_atributo y
nombre_de_método, han de ser identificadores Java válidos.
b.) Los atributos
Los datos se encapsulan dentro de una clase declarando variables dentro de las llaves de
apertura y cierre de la declaración de la clase, variables que se conocen como atributos.
Se declaran igual que las variables locales de un método en concreto.
Por ejemplo, este es un programa que declara una clase MiPunto, con dos atributos
enteros llamados x e y.
class MiPunto {
int x, y;
Los atributos se pueden declarar con dos clases de tipos: un tipo simple Java (ya
descritos), o el nombre de una clase (será una referencia a objeto, véase el punto C.a de
este mismo apartado).
Cuando se realiza una instancia de una clase (creación de un objeto) se reservará en la
memoria un espacio para un conjunto de datos como el que definen los atributos de una
clase. A este conjunto de variables se le denomina variables de instancia.
c.) Los métodos
Los métodos son subrutinas que definen la interfaz de una clase, sus capacidades y
comportamiento.
Un método ha de tener por nombre cualquier identificador legal distinto de los ya
utilizados por los nombres de la clase en que está definido. Los métodos se declaran al
mismo nivel que las variables de instancia dentro de una definición de clase.
En la declaración de los métodos se define el tipo de valor que devuelven y a una lista
formal de parámetros de entrada, de sintaxis tipo identificador separadas por comas. La
forma general de una declaración de método es:
tipo_devuelto nombre_de_método( lista-formal-de-
parámetros ) {
cuerpo_del_método;
En el caso de que no se desee devolver ningún valor se deberá indicar como tipo la
palabra reservada void. Así mismo, si no se desean parámetros, la declaración del
método debería incluir un par de paréntesis vacíos (sin void):
void metodoVacio( ) { };
Los métodos son llamados indicando una instancia individual de la clase, que tendrá su
propio conjunto único de variables de instancia, por lo que los métodos se pueden
referir directamente a ellas.
El método inicia() para establecer valores a las dos variables de instancia sería el
siguiente:
void inicia( int paramX, int paramY ) {
x = paramX;
y = paramY;
inicia( -1, -1 );
La lista de parámetros especificada después del nombre de una clase en una sentencia
new se utiliza para pasar parámetros al constructor.
Se llama al método constructor justo después de crear la instancia y antes de que new
devuelva el control al punto de la llamada.
Así, cuando ejecutamos el siguiente programa:
MiPunto p1 = new MiPunto(10, 20);
System.out.println( "p1.- x = " + p1.x + " y = " + p1.y );
Se muestra en la pantalla:
p1.- x = 10 y = 20
Para crear un programa Java que contenga ese código, se debe de crear una clase que
contenga un método main(). El intérprete java se ejecutará el método main de la clase
que se le indique como parámetro.
Para más información sobre cómo crear y ejecutar un programa, así como los tipos de
programas que se pueden crear en Java, véase el capítulo "II.12. Creación de
programas Java" de este tutorial.
c.) El operador new
El operador new crea una instancia de una clase (objetos) y devuelve una referencia a
ese objeto. Por ejemplo:
MiPunto p2 = new MiPunto(2,3);
Este es un ejemplo de la creación de una instancia de MiPunto, que es controlador por la
referencia a objeto p2.
Hay una distinción crítica entre la forma de manipular los tipos simples y las clases en
Java: Las referencias a objetos realmente no contienen a los objetos a los que
referencian. De esta forma se pueden crear múltiples referencias al mismo objeto, como
por ejemplo:
MiPunto p3 =p2;
Aunque tan sólo se creó un objeto MiPunto, hay dos variables (p2 y p3) que lo
referencian. Cualquier cambio realizado en el objeto referenciado por p2 afectará al
objeto referenciado por p3. La asignación de p2 a p3 no reserva memoria ni modifica el
objeto.
De hecho, las asignaciones posteriores de p2 simplemente desengancharán p2 del
objeto, sin afectarlo:
p2 = null; // p3 todavía apunta al objeto creado con new
Aunque se haya asignado null a p2, p3 todavía apunta al objeto creado por el operador
new.
Cuando ya no haya ninguna variable que haga referencia a un objeto, Java reclama
automáticamente la memoria utilizada por ese objeto, a lo que se denomina recogida de
basura.
Cuando se realiza una instancia de una clase (mediante new) se reserva en la memoria
un espacio para un conjunto de datos como el que definen los atributos de la clase que
se indica en la instanciación. A este conjunto de variables se le denomina variables de
instancia.
La potencia de las variables de instancia es que se obtiene un conjunto distinto de ellas
cada vez que se crea un objeto nuevo. Es importante el comprender que cada objeto
tiene su propia copia de las variables de instancia de su clase, por lo que los cambios
sobre las variables de instancia de un objeto no tienen efecto sobre las variables de
instancia de otro.
El siguiente programa crea dos objetos MiPunto y establece los valores de x e y de cada
uno de ellos de manera independiente para mostrar que están realmente separados.
MiPunto p4 = new MiPunto( 10, 20 );
MiPunto p5 = new MiPunto( 42, 99 );
System.out.println("p4.- x = " + p4.x + " y = " + p4.y);
System.out.println("p5.- x = " + p5.x + " y = " + p5.y);
Este es el aspecto de salida cuando lo ejecutamos.
p4.- x = 10 y = 20
p5.- x = 42 y = 99
D. Acceso al objeto
a.) El operador punto (.)
El operador punto (.) se utiliza para acceder a las variables de instancia y los métodos
contenidos en un objeto, mediante su referencia a objeto:
referencia_a_objeto.nombre_de_variable_de_instancia
referencia_a_objeto.nombre_de_método( lista-de-
parámetros );
Hemos creado un ejemplo completo que combina los operadores new y punto para crear
un objeto MiPunto, almacenar algunos valores en él e imprimir sus valores finales:
MiPunto p6 = new MiPunto( 10, 20 );
System.out.println ("p6.- 1. X=" + p6.x + " , Y=" + p6.y);
p6.inicia( 30, 40 );
System.out.println ("p6.- 2. X=" + p6.x + " , Y=" + p6.y);
Cuando se ejecuta este programa, se observa la siguiente salida:
p6.- 1. X=10 , Y=20
p6.- 2. X=30 , Y=40
Durante las impresiones (método println()) se accede al valor de las variables mediante
p6.x y p6.y, y entre una impresión y otra se llama al método inicia(), cambiando los
valores de las variables de instancia.
Este es uno de los aspectos más importantes de la diferencia entre la programación
orientada a objetos y la programación estructurada. Cuando se llama al método
p6.inicia(), lo primero que se hace en el método es sustituir los nombres de los atributos
de la clase por las correspondientes variables de instancia del objeto con que se ha
llamado. Así por ejemplo x se convertirá en p6.x.
Si otros objetos llaman a inicia(), incluso si lo hacen de una manera concurrente, no se
producen efectos laterales, ya que las variables de instancia sobre las que trabajan son
distintas.
b.) La referencia this
Java incluye un valor de referencia especial llamado this, que se utiliza dentro de
cualquier método para referirse al objeto actual. El valor this se refiere al objeto sobre el
que ha sido llamado el método actual. Se puede utilizar this siempre que se requiera una
referencia a un objeto del tipo de una clase actual. Si hay dos objetos que utilicen el
mismo código, seleccionados a través de otras instancias, cada uno tiene su propio valor
único de this.
Un refinamiento habitual es que un constructor llame a otro para construir la instancia
correctamente. El siguiente constructor llama al constructor parametrizado
MiPunto(x,y) para terminar de iniciar la instancia:
MiPunto() {
ClaseFinalizada() { // Constructor
// Reserva del recurso no Java o recurso compartido
II.6. LA HERENCIA
A. Introducción
La verdadera potencia de la programación orientada a objetos radica en su capacidad
para reflejar la abstracción que el cerebro humano realiza automáticamente durante el
proceso de aprendizaje y el proceso de análisis de información.
Las personas percibimos la realidad como un conjunto de objetos interrelacionados.
Dichas interrelaciones, pueden verse como un conjunto de abstracciones y
generalizaciones que se han ido asimilando desde la niñez. Así, los defensores de la
programación orientada a objetos afirman que esta técnica se adecua mejor al
funcionamiento del cerebro humano, al permitir descomponer un problema de cierta
magnitud en un conjunto de problemas menores subordinados del primero.
La capacidad de descomponer un problema o concepto en un conjunto de objetos
relacionados entre sí, y cuyo comportamiento es fácilmente identificable, puede ser muy
útil para el desarrollo de programas informáticos.
B. Jerarquía
La herencia es el mecanismo fundamental de relación entre clases en la orientación a
objetos. Relaciona las clases de manera jerárquica; una clase padre o superclase sobre
otras clases hijas o subclases.
// Contenido de la clase
Por ejemplo, creamos una clase MiPunto3D, hija de la clase ya mostrada MiPunto:
class MiPunto3D extends MiPunto {
int z;
MiPunto3D( ) {
x = 0; // Heredado de MiPunto
y = 0; // Heredado de MiPunto
z = 0; // Nuevo atributo
La palabra clave extends se utiliza para decir que deseamos crear una subclase de la
clase que es nombrada a continuación, en nuestro caso MiPunto3D es hija de MiPunto.
E. Limitaciones en la herencia
Todos los campos y métodos de una clase son siempre accesibles para el código de la
misma clase.
Para controlar el acceso desde otras clases, y para controlar la herencia por las subclase,
los miembros (atributos y métodos) de las clases tienen tres modificadores posibles de
control de acceso:
• public: Los miembros declarados public son accesibles en cualquier lugar en que
sea accesible la clase, y son heredados por las subclases.
• private: Los miembros declarados private son accesibles sólo en la propia clase.
• protected: Los miembros declarados protected son accesibles sólo para sus
subclases
Por ejemplo:
class Padre { // Hereda de Object
// Atributos
// Métodos
return numeroFavorito;
return nacidoHace;
}
return dineroDisponible;
// Definición
class Visita {
// Definición
En este ejemplo, un objeto de la clase Hija, hereda los tres atributos (numeroFavorito,
nacidoHace y dineroDisponible) y los tres métodos ( getApuesta(), getEdad() y
getSaldo() ) de la clase Padre, y podrá invocarlos. Cuando se llame al método
getEdad() de un objeto de la clase Hija, se devolverá el valor de la variable de instancia
nacidoHace de ese objeto, y no de uno de la clase Padre.
Sin embargo, un objeto de la clase Hija, no podrá invocar al método getSaldo() de un
objeto de la clase Padre, con lo que se evita que el Hijo conozca el estado de la cuenta
corriente de un Padre.
La clase Visita, solo podrá acceder al método getApuesta(), para averiguar el número
favorito de un Padre, pero de ninguna manera podrá conocer ni su saldo, ni su edad
(sería una indiscreción, ¿no?).
F. La clase Object
La clase Object es la superclase de todas las clases da Java. Todas las clases derivan,
directa o indirectamente de ella. Si al definir una nueva clase, no aparece la cláusula
extends, Java considera que dicha clase desciende directamente de Object.
La clase Object aporta una serie de funciones básicas comunes a todas las clases:
• public boolean equals( Object obj ): Se utiliza para comparar, en valor, dos
objetos. Devuelve true si el objeto que recibe por parámetro es igual, en valor,
que el objeto desde el que se llama al método. Si se desean comparar dos
referencias a objeto se pueden utilizar los operadores de comparación == y !=.
• public int hashCode(): Devuelve un código hash para ese objeto, para poder
almacenarlo en una Hashtable.
• protected Object clone() throws CloneNotSupportedException: Devuelve una
copia de ese objeto.
• public final Class getClass(): Devuelve el objeto concreto, de tipo Class, que
representa la clase de ese objeto.
• protected void finalize() throws Trowable: Realiza acciones durante la recogida
de basura.
Para más información véase [Arnold y Gosling, 1997].
void metodoConcreto() {
void metodoAbstracto(){
}
La clase abstracta claseA ha implementado el método concreto metodoConcreto(), pero
el método metodoAbstracto() era abstracto y por eso ha tenido que ser redefinido en la
clase hija claseB.
claseA referenciaA = new claseB();
referenciaA.metodoAbstracto();
referenciaA.metodoConcreto();
La salida de la ejecución del programa es:
En el metodo abstracto de claseB
En el metodo concreto de claseA
C. El polimorfismo
a.) Selección dinámica de método
Las dos clases implementadas a continuación tienen una relación subclase/superclase
simple con un único método que se sobrescribe en la subclase:
class claseAA {
void metodoDinamico() {
void metodoDinamico() {
int x,y,z;
int retorno=0;
retorno += ((x/z)-pX)*((x/z)-pX);
retorno += ((y/z)-pY)*((y/z)-pY);
inicia( -1, -1 );
this.x = paramX;
y = paramY;
extremo1=new MiPunto();
extremo2=new MiPunto();
return true;
else
return false;
Puede observarse que las referencias a objeto (extremo1 y extremo2) son iniciadas,
instanciando un objeto para cada una en el constructor. Así esta clase mediante dos
puntos, referenciados por extremo1 y extremo2, establece unos límites de su área, que
serán utilizados para comprobar si un punto está en su área en el método
estaEnElArea().
return ERROR;
B. Tipos de excepciones
Existen varios tipos fundamentales de excepciones:
• Error: Excepciones que indican problemas muy graves, que suelen ser no
recuperables y no deben casi nunca ser capturadas.
• Exception: Excepciones no definitivas, pero que se detectan fuera del tiempo de
ejecución.
• RuntimeException: Excepciones que se dan durante la ejecución del programa.
Pero lo importante es cómo controlar qué hacer con la posible excepción que se cree.
Para ello se utilizan las clausulas catch, en las que se especifica que acción realizar:
try {
} catch( tipo_de_excepcion e) {
} catch( tipo_de_excepcion_mas_general e) {
En el ejemplo se observa que se pueden anidar sentencias catch, pero conviene hacerlo
indicando en último lugar las excepciones más generales (es decir, que se encuentren
más arriba en el árbol de herencia de excepciones), porque el intérprete Java ejecutará
aquel bloque de código catch cuyo parámetro sea del tipo de una excepción lanzada.
Si por ejemplo se intentase capturar primero una excepción Throwable, nunca
llegaríamos a gestionar una excepción Runtime, puesto que cualquier clase hija de
Runtime es también hija de Throwable, por herencia.
Si no se ha lanzado ninguna excepción el código continúa sin ejecutar ninguna sentencia
catch.
Pero, ¿y si quiero realizar una acción común a todas las opciones?. Para insertar
fragmentos de código que se ejecuten tras la gestión de las excepciones. Este código se
ejecutará tanto si se ha tratado una excepción (catch) como sino. Este tipo de código se
inserta en una sentencia finally, que será ejecutada tras el bloque try o catch:
try {
} catch( Exception e ) {
} finally {
Se puede observar que hemos creado un objeto de la clase miExcepcion, puesto que las
excepciones son objetos y por tanto deberán ser instanciadas antes de ser lanzadas.
Aquellos métodos que pueden lanzar excepciones, deben cuáles son esas excepciones en
su declaración. Para ello se utiliza la sentencia throws:
tipo_devuelto miMetodoLanzador() throws miExcep1, miExcep2
{
Se puede observar que cuando se pueden lanzar en el método más de una excepción se
deben indicar en su declaración separadas por comas.
d.) Ejemplo de gestión de excepciones
Ahora que ya sabemos cómo funciona este sistema, conviene ver al menos un pequeño
ejemplo, que ilustre al lector en el uso de las excepciones:
// Creo una excepción personalizada
MiExcepcion(){
class Lanzadora {
if ( param < 0 )
class Excepciones {
int leo;
try {
lanza.lanzaSiNegativo( leo );
entrada.close();
} finally {
if ( entrada != null )
try {
} catch ( Exception e ) {
System.out.println( "Excepcion: " +
e.getMessage() );
class Excepciones {
int leo;
try {
lanza.lanzaSiNegativo( leo );
} finally {
II.9. INTERFACES
A. Introducción
Las interfaces Java son expresiones puras de diseño. Se trata de auténticas
conceptualizaciones no implementadas que sirven de guía para definir un determinado
concepto (clase) y lo que debe hacer, pero sin desarrollar un mecanismo de solución.
Se trata de declarar métodos abstractos y constantes que posteriormente puedan ser
implementados de diferentes maneras según las necesidades de un programa.
Por ejemplo una misma interfaz podría ser implementada en una versión de prueba de
manera poco óptima, y ser acelerada convenientemente en la versión definitiva tras
conocer más a fondo el problema.
B. Declaración
Para declarar una interfaz se utiliza la sentencia interface, de la misma manera que se
usa la sentencia class:
interface MiInterfaz {
int multiplicando=CONSTANTE;
En este ejemplo se observa que han de codificarse todos los métodos que determina la
interfaz (metodoAbstracto()), y la validez de las constantes (CONSTANTE) que define
la interfaz durante toda la declaración de la clase.
Una interfaz no puede implementar otra interfaz, aunque sí extenderla (extends)
ampliándola.
D. Herencia múltiple
Java es un lenguaje que incorpora herencia simple de implementación pero que puede
aportar herencia múltiple de interfaz. Esto posibilita la herencia múltiple en el diseño de
los programas Java.
Una interfaz puede heredar de más de una interfaz antecesora.
interface InterfazMultiple extends Interfaz1,Interfaz2{ }
Una clase no puede tener más que una clase antecesora, pero puede implementar más de
una interfaz:
class MiClase extends SuPadre implements
Interfaz1,Interfaz2{ }
El ejemplo típico de herencia múltiple es el que se presenta con la herencia en diamante:
Imagen 6: Ejemplo de herencia múltiple
Para poder llevar a cabo un esquema como el anterior en Java es necesario que las
clases A, B y C de la figura sean interfaces, y que la clase D sea una clase (que recibe la
herencia múltiple):
interface A{ }
interface B extends A{ }
interface C extends A{ }
class D implements B,C{ }
E. Colisiones en la herencia múltiple
En una herencia múltiple, los identificadores de algunos métodos o atributos pueden
coincidir en la clase que hereda, si dos de las interfaces padres tienen algún método o
atributo que coincida en nombre. A esto se le llama colisión.
Esto se dará cuando las clases padre (en el ejemplo anterior B y C) tienen un atributo o
método que se llame igual. Java resuelve el problema estableciendo una serie de reglas.
Para la colisión de nombres de atributos, se obliga a especificar a qué interfaz base
pertenecen al utilizarlos.
Para la colisión de nombres en métodos:
• Si tienen el mismo nombre y diferentes parámetros: se produce sobrecarga de
métodos permitiendo que existan varias maneras de llamar al mismo.
• Si sólo cambia el valor devuelto: se da un error de compilación, indicando que
no se pueden implementar los dos.
• Si coinciden en su declaración: se elimina uno de los dos, con lo que sólo queda
uno.
F. Envolturas de los tipos simples
Los tipos de datos de Java no forman parte de la jerarquía de objetos. Sin embargo a
veces es necesario crear una representación como objeto de alguno de los tipos de datos
simples de Java.
La API de Java contiene un conjunto de interfaces especiales para modificar el
comportamiento de los tipos de datos simple. A estas interfaces se las conoce como
envolturas de tipo simple.
Todas ellas son hijas de la clase abstracta Number y son:
• Double: Da soporte al tipo double.
• Float: Da soporte al tipo float.
• Integer: Da soporte a los tipos int, short y byte.
• Long: Da soporte al tipo long.
• Character: Envoltura del tipo char.
• Boolean: Envoltorio al tipo boolean.
Para más información sobre as envolturas de tipos simples, consúltese [Naughton,
1996].
II.10. PAQUETES
A. Introducción
Los paquetes son el mecanismo por el que Java permite agrupar clases, interfaces,
excepciones y constantes. De esta forma, se agrupan conjuntos de estructuras de datos y
de clases con algún tipo de relación en común.
Con la idea de mantener la reutilización y facilidad de uso de los paquetes desarrollados
es conveniente que las clases e interfaces contenidas en los mismos tengan cierta
relación funcional. De esta manera los desarrolladores ya tendrán una idea de lo que
están buscando y fácilmente sabrán qué pueden encontrar dentro de un paquete.
B. Creación de un paquete
a.) Declaración
Para declarar un paquete se utiliza la sentencia package seguida del nombre del paquete
que estemos creando:
package NombrePaquete;
La estructura que ha de seguir un fichero fuente en Java es:
• Una única sentencia de paquete (opcional).
• Las sentencias de importación deseadas (opcional).
• La declaración de una (y sólo una) clase pública (public).
• Las clases privadas del paquete (opcional).
Por lo tanto la sentencia de declaración de paquete ha de ser la primera en un archivo
fuente Java.
b.) Nomenclatura
Para que los nombres de paquete puedan ser fácilmente reutilizados en toda una
compañía o incluso en todo el mundo es conveniente darles nombres únicos. Esto puede
ser una tarea realmente tediosa dentro de una gran empresa, y absolutamente imposible
dentro de la comunidad de Internet.
Por eso se propone asignar como paquetes y subpaquetes el nombre de dominio dentro
de Internet. Se verá un ejemplo para un dominio que se llamase japon.magic.com, un
nombre apropiado sería com.magic.japon.paquete.
c.) Subpaquetes
Cada paquete puede tener a su vez paquetes con contenidos parecidos, de forma que un
programador probablemente estará interesado en organizar sus paquetes de forma
jerárquica. Para eso se definen los subpaquetes.
Para crear un subpaquete bastará con almacenar el paquete hijo en un directorio
Paquete/Subpaquete.
Así una clase dentro de un subpaquete como Paquete.Subpaquete.clase estará
codificada en el fichero Paquete/Subpaquete.java.
El JDK define una variable de entorno denominada CLASSPATH que gestiona las rutas
en las que el JDK busca los subpaquetes. El directorio actual suele estar siempre
incluido en la variable de entorno CLASSPATH.
Para más información sobre el JDK véase el "Apéndice I. JDK" de este tutorial.
C. Uso de un paquete
Con el fin de importar paquetes ya desarrollados se utiliza la sentencia import seguida
del nombre de paquete o paquetes a importar.
Se pueden importar todos los elementos de un paquete o sólo algunos.
Para importar todas las clases e interfaces de un paquete se utiliza el metacaracter *:
import PaquetePrueba.*;
También existe la posibilidad de que se deseen importar sólo algunas de las clases de un
cierto paquete o subpaquete:
import Paquete.Subpaquete1.Subpaquete2.Clase1;
Para acceder a los elementos de un paquete, no es necesario importar explícitamente el
paquete en que aparecen, sino que basta con referenciar el elemento tras una
especificación completa de la ruta de paquetes y subpaquetes en que se encuentra.
Paquete.Subpaquetes1.Subpaquete2.Clase_o_Interfaz.elemento
En la API de Java se incluyen un conjunto de paquetes ya desarrollados que se pueden
incluir en cualquier aplicación (o applet) Java que se desarrolle. Estos paquetes son
explicados con más detalle en el capítulo "III.1.Bibliotecas de la API de Java" de este
tutorial.
D. Ámbito de los elementos de un paquete
Al introducir el concepto de paquete, surge la duda de cómo proteger los elementos de
una clase, qué visibilidad presentan respecto al resto de elementos del paquete, respecto
a los de otros paquetes...
Ya en la herencia se vieron los identificadores de visibilidad public (visible a todas las
clases), private (no visible más que para la propia clase), y protected (visible a clases
hijas).
Por defecto se considera los elementos (clases, variables y métodos) de un mismo
paquete como visibles entre ellos (supliendo las denominadas clases amigas de C++).
En la misma clase Sí Sí Sí Sí
En una clase No Sí Sí Sí
en el mismo paquete
import java.net.*;
ThreadDemo() {
thDemo.start();
try {
Thread.sleep(3000);
} catch( InterruptedException e ) { }
new ThreadDemo();
try {
Thread.sleep(1000);
}
} catch( InterruptedException e ) { }
Ambos hilos esperan utilizando el método sleep() de la clase Thread; thDemo tres
segundos, y main cinco segundos. Java utilizará los tres segundos de thDemo para ir
esperando los tres primeros segundos del hilo main.
Por lo tanto la salida por pantalla al ejecutar el programa es:
prompt> java ThreadDemo
Seg: 5
Seg: 4
Seg: 3
Saliendo del hilo hijo
Seg: 2
Seg: 1
Saliendo del hilo main
C. Sincronización de threads
Durante la ejecución de un programa, muchas veces varios procesos han de realizar
tareas de una forma sincronizada, actuando en un determinado orden. Para ello en Java
se utilizan la palabra reservada syncronized, en la declaración de los procesos con este
tipo de características.
Los procesos declarados como syncronized mediante la utilización de excepciones, y de
las funciones wait() y notifiy(), respectivamente esperarán a que otro proceso acabe
antes de continuar su ejecución.
A continuación se va a ir viendo cómo implementar el clásico problema de exclusión
mutua conocido como el problema del productor/consumidor, en el que dos procesos
han de acceder a una cola común, en la que el proceso productor inserta elementos en la
pila, y el proceso consumidor ha de ir consumiendo los elementos en la pila, cada vez
que sean insertados:
class ColaSincronizada {
int n;
if ( !bandera )
bandera = false;
notify();
return n;
if ( bandera )
n = paramN;
bandera =true;
notify();
colaProductor = paramCola;
int i = 0;
colaProductor.coloca( i++ );
ColaSincronizada colaConsumidor;
colaConsumidor = paramCola;
III.2. CADENAS
A. Introducción
a.) Introducción a las clases String y StringBuffer
En Java las cadenas se tratan de forma diferente a C/C++, donde las cadenas son
matrices de caracteres en las que se indica el final de la cadena con un carácter de valor
‘\0’.
En Java las cadenas son objetos de las clases predefinida String o StringBuffer, que
están incluidas en el paquete java.lang.*.
Siempre que aparecen conjuntos de caracteres entre comillas dobles, el compilador de
Java crea automáticamente un objeto String.
Si sólo existieran cadenas de sólo lectura (String), durante una serie de manipulaciones
sobre un objeto String habría que crear un nuevo objeto para cada uno de los resultados
intermedios.
El compilador es más eficiente y usa un objeto StringBuffer para construir cadenas a
partir de las expresiones, creando el String final sólo cuando es necesario. Los objetos
StringBuffer se pueden modificar, de forma que no son necesarios nuevos objetos para
albergar los resultados intermedios.
Los caracteres de las cadenas tienen un índice que indica su posición. El primer carácter
de una cadena tiene el índice 0, el segundo el 1, el tercero el 2 y así sucesivamente. Esto
puede sonar familiar a los programadores de C/C++, pero resultar chocante para
aquellos programadores que provengan de otros lenguajes.
b.) Operaciones básicas, comunes a String y StringBuffer
Existen una serie de métodos que son comunes a ambas clases.
Los siguientes métodos de acceso a las cadenas:
• int length(); Devuelve el número de caracteres de la cadena.
• char charAt( int i ); Devuelve el carácter correspondiente de índice i.
Los siguientes métodos para crear cadenas derivadas:
• String toString(); Devuelve una copia del objeto como una String.
• String substring( int i, int fin ); Devuelve una instancia de la clase String que
contenga una subcadena desde la posición ini, hasta la fin (si no se indica hasta
el final de la cadena), del objeto cadena que invoque el método.
Y el método para transformar la cadena en un vector de caracteres:
• void getChars(int ini, int fin, char[] destino, int destIni); Convierte la cadena en
un vector de caracteres destino.
B. Métodos de la clase String
a.) Constructores
La clase String proporciona cadenas de sólo lectura y soporta operaciones con ellas. Se
pueden crear cadenas implícitamente mediante una cadena entrecomillada o usando + ó
+= con dos objetos String.
También se pueden crear objetos String explícitamente con el mecanismo new.
La clase String soporta multitud de constructores.
• String(); Constructor por defecto. El nuevo String toma el valor "".
• String( String s ); Crea un nuevo String, copiando el que recibe por parámetro.
• String( StringBuffer s ); Crea un String con el valor que en ese momento tenga el
StringBuffer que recibe como parámetro.
• String( char[] v ); El nuevo String toma el valor de los caracteres que tiene el
vector de caracteres recibido por parámetro.
• String( byte[] v ); El nuevo String toma el valor de los caracteres que
corresponden a los valores del vector de bytes en el sistema de caracteres de la
ordenador en que se ejecute.
b.) Búsqueda en cadenas String
Además presenta los siguientes métodos para buscar caracteres o subcadenas en la
cadena, y devuelven el índice que han encontrado o el valor –1 si la búsqueda no ha sido
satisfactoria:
• int indexOf( char ch, int start ): Devuelve el índice correspondiente a la primera
aparición del carácter ch en la cadena, comenzando a buscar desde el carácter
start (si no se especifica se busca desde el principio).
• int indexOf( String str ): Devuelve el índice correspondiente al carácter en que
empieza la primera aparición de la subcadena str.
• int lastIndexOf( char ch, int start ): Devuelve el índice correspondiente a la
última aparición del carácter ch en la cadena, comenzando a buscar desde el
carácter start (si no se especifica se busca desde el final).
• int lastIndexOf( String str ): Devuelve el índice correspondiente al carácter en
que empieza la última aparición de la subcadena str.
c.) Comparaciones de cadenas String
Java no trabaja con el código ASCII habitual, sino con el código avanzado Unicode.
El código Unicode (código universal) se caracteriza, sobre todo, por el uso de dos bytes
por carácter. Esto permite aumentar los caracteres hasta 65000, y así se pueden
representar los caracteres que componen las lenguas, vivas o muertas, más importantes
del mundo.
Hay que tener en cuenta que si nos salimos del rango 0-255 que coincide con el código
ASCII puede que las comparaciones no sean las esperadas.
Las funciones de comparación son las siguientes:
• boolean equals( Object o ); Devuelve true si se le pasa una referencia a un
objeto String con los mismos caracteres, o false si no.
• boolean equalsIgnoreCase( String s ); Compara cadenas ignorando las
diferencias de ortografía mayúsculas/minúsculas.
• boolean regionMatches( boolean b, int o, String s , int i, int n ); Compara parte
de dos cadenas, carácter a carácter.
• boolean startsWith( String s, int i ); Comprueba si la cadena tiene el prefijo s
desde i.
• boolean endsWith( String s ); Comprueba si la cadena termina con el sufijo s.
• int compareTo( Object o ); Devuelve un entero que es menor, igual o mayor que
cero cuando la cadena sobre la que se le invoca es menor, igual o mayor que la
otra. Si el parámetro es un String, la comparación es léxica.
• int compareToIgnoraCase( String s ); Compara lexicográficamente, ignorando
las diferencias de ortografía mayúsculas/minúsculas.
d.) Cadenas String derivadas
En Java se devuelven nuevas cadenas cada vez que se invoca a un método que crea una
cadena diferente porque las cadenas String son de sólo lectura:
• String replace( char oldChar, char newChar ); Devuelve una nueva cadena con
todos los caracteres oldChar sustituidos por el carácter newChar.
• String toLowerCase(); Devuelve una nueva cadena con los caracteres en
minúsculas, o si se especifica parámetro, siguiendo sus reglas.
• String toUperCase( Locale l ); Devuelve una nueva cadena con los caracteres en
mayúsculas, o si se especifica parámetro, siguiendo sus reglas.
• static String trim(): Devuelve una nueva cadena del que se ha eliminado los
espacios en blanco por el principio y por el final.
• static String copyValueOf( char[] v, int ini, int fin ); Devuelve una cadena igual
que la contenida en el vector v, entre los límites ini y fin (si no se especifican
copia todo el vector).
• static String concat( String s ); Concatena la cadena que recibe al final de ésta.
e.) Conversiones entre cadenas String y tipos simples Java
Para convertir una variable de un tipo de datos simple (char, boolean, int, long, float,
double) en una cadena (String), bastará con invocar al método valueOf() del objeto
String correspondiente:
• static String valueOf( tipo ); El parámetro tipo soporta un carácter (char) un
vector de caracteres (char[]) o un objeto (Object).
Sin embargo para convertir el valor de una cadena en un tipo de datos simple deberemos
utilizar los siguientes métodos:
Tipo De String
System.out.println( cad.substring(2,6) );
System.out.print( vectorcad[2] );
// Búsqueda en cadenas
System.out.println( cad.indexOf(subcad) );
// Comparaciones
if ( cad.compareTo(cadcomp) == 0 )
else
System.out.println(" NO es igual 'Sensitive'");
if ( cad.equalsIgnoreCase(cadcomp) )
else
System.out.println(" NO = 'Insensitive'");
// Derivación
System.out.println( cad.toLowerCase() );
cad.delete( 0, 6 );
cad.append(" Cadena");
// Gestión de su capacidad
cad.ensureCapacity( 32 );
System.out.println("");
III.3. ENTRADA/SALIDA
A. Introducción
Normalmente, cuando se codifica un programa, se hace con la intención de que ese
programa pueda interactuar con los usuarios del mismo, es decir, que el usuario pueda
pedirle que realice cosas y pueda suministrarle datos con los que se quiere que haga
algo. Una vez introducidos los datos y las órdenes, se espera que el programa manipule
de alguna forma esos datos para proporcionarnos una respuesta a lo solicitado.
Además, en muchas ocasiones interesa que el programa guarde los datos que se le han
introducido, de forma que si el programa termina los datos no se pierdan y puedan ser
recuperados en una sesión posterior. La forma más normal de hacer esto es mediante la
utilización de ficheros que se guardarán en un dispositivo de memoria no volátil
(normalmente un disco).
A todas estas operaciones, que constituyen un flujo de información del programa con el
exterior, se les conoce como Entrada/Salida (E/S).
Existen dos tipos de E/S; la E/S estándar que se realiza con el terminal del usuario y la
E/S a través de fichero, en la que se trabaja con ficheros de disco.
Todas las operaciones de E/S en Java vienen proporcionadas por el paquete estándar de
la API de Java denominado java.io que incorpora interfaces, clases y excepciones para
acceder a todo tipo de ficheros. En este tutorial sólo se van a dar algunas pinceladas de
la potencia de este paquete.
B. Entrada/Salida estándar
Aquí sólo trataremos la entrada/salida que se comunica con el usuario a través de la
pantalla o de la ventana del terminal.
Si creamos una applet no se utilizarán normalmente estas funciones, ya que su resultado
se mostrará en la ventana del terminal y no en la ventana de la applet. La ventana de la
applet es una ventana gráfica y para poder realizar una entrada o salida a través de ella
será necesario utilizar el AWT.
El acceso a la entrada y salida estándar es controlado por tres objetos que se crean
automáticamente al iniciar la aplicación: System.in, System.out y System.err
a.) System.in
Este objeto implementa la entrada estándar (normalmente el teclado). Los métodos que
nos proporciona para controlar la entrada son:
• read(): Devuelve el carácter que se ha introducido por el teclado leyéndolo del
buffer de entrada y lo elimina del buffer para que en la siguiente lectura sea
leído el siguiente carácter. Si no se ha introducido ningún carácter por el teclado
devuelve el valor -1.
• skip(n): Ignora los n caracteres siguientes de la entrada.
b.) System.out
Este objeto implementa la salida estándar. Los métodos que nos proporciona para
controlar la salida son:
• print(a): Imprime a en la salida, donde a puede ser cualquier tipo básico Java ya
que Java hace su conversión automática a cadena.
• println(a): Es idéntico a print(a) salvo que con println() se imprime un salto de
línea al final de la impresión de a.
c.) System.err
Este objeto implementa la salida en caso de error. Normalmente esta salida es la
pantalla o la ventana del terminal como con System.out, pero puede ser interesante
redirigirlo, por ejemplo hacia un fichero, para diferenciar claramente ambos tipos de
salidas.
Las funciones que ofrece este objeto son idénticas a las proporcionadas por System.out.
d.) Ejemplo
A continuación vemos un ejemplo del uso de estas funciones que acepta texto hasta que
se pulsa el retorno de carro e informa del número de caracteres introducidos.
import java.io.*;
class CuentaCaracteres {
int contador=0;
while(System.in.read()!='\n')
contador++;
System.out.println("Tecleados "+contador+"
caracteres.");
class CreaCarta {
int c;
while( ( c=System.in.read() ) != -1 )
f.write( (char)c );
f.close();
class MuestraCarta {
int c;
while( ( c=f.read() ) != -1 )
System.out.print( (char)c );
f.close();
try{
f.writeByte( i );
f.close();
System.out.println( f.readByte() );
f.close();
Si incluimos ambos métodos en una clase, y les llamamos con el siguiente programa
principal (main()):
public static void main(String args[]) throws IOException {
}
Obtendremos la siguiente salida:
El fichero numeros.dat ocupa 100 bytes.
En la posicion 13 esta el numero 14
10 elementos más allá, esta el 24
import java.net.*;
class Cliente {
try{
System.out.println( flujo.readUTF() );
skCliente.close();
} catch( Exception e ) {
System.out.println( e.getMessage() );
new Cliente();
import java.net.* ;
class Servidor {
public Servidor( ) {
try {
skCliente.close();
}
} catch( Exception e ) {
System.out.println( e.getMessage() );
new Servidor();
Utiliza un objeto de la clase ServerSocket (skServidor), que sirve para esperar las
conexiones en un puerto determinado (PUERTO), y un objeto de la clase Socket
(skCliente) que sirve para gestionar una conexión con cada cliente.
Mediante un bucle for y la variable numCli se restringe el número de clientes a tres, con
lo que cada vez que en el puerto de este servidor aparezca un cliente, se atiende y se
incrementa el contador.
Para atender a los clientes se utiliza la primitiva accept() de la clase ServerSocket, que
es una rutina que crea un nuevo Socket (skCliente) para atender a un cliente que se ha
conectado a ese servidor.
Se asocia al socket creado (skCliente) un flujo (flujo) de salida DataOutputStream de
escritura secuencial, en el que se escribe el mensaje a enviar al cliente.
El tratamiento de las excepciones es muy reducido en nuestro ejemplo, tan solo se
captura e imprime el mensaje que incluye la excepción mediante getMessage().
c.) Ejecución
Aunque la ejecución de los sockets está diseñada para trabajar con ordenadores en red,
en sistemas operativos multitarea (por ejemplo Windows y UNIX) se puede probar el
correcto funcionamiento de un programa de sockets en una misma máquina.
Para ellos se ha de colocar el servidor en una ventana, obteniendo lo siguiente:
>java Servidor
Escucho el puerto 5000
En otra ventana se lanza varias veces el programa cliente, obteniendo:
>java Cliente
Hola cliente 1
>java cliente
Hola cliente 2
>java cliente
Hola cliente 3
>java cliente
connection refused: no further information
Mientras tanto en la ventana del servidor se ha impreso:
Sirvo al cliente 1
Sirvo al cliente 2
Sirvo al cliente 3
Demasiados clientes por hoy
Cuando se lanza el cuarto de cliente, el servidor ya ha cortado la conexión, con lo que se
lanza una excepción.
Obsérvese que tanto el cliente como el servidor pueden leer o escribir del socket. Los
mecanismos de comunicación pueden ser refinados cambiando la implementación de los
sockets, mediante la utilización de las clases abstractas que el paquete java.net provee.
return info;
import java.applet.*;
g.setColor( Color.red );
import java.awt.event.*;
unaApplet=new AppletDiagonal();
unaApplet.init();
unaApplet.start();
// Clase anidada
unaApplet.stop();
unaApplet.destroy();
System.exit(0);
Vamos a crear un Frame en el que vamos a incluir la applet unaApplet que será de la
clase AppletDiagonal, creada anteriormente.
La aplicación lo que hace es crear un oyente de la clase creada OyenteLinea, que será el
encargado de capturar el evento de cerrar la ventana del Frame.
En el constructor se inicia la applet (init() y start()) y se añade al Frame mediante el
método add() de la clase Container (Frame es hija de Container).
Por último se establece el tamaño del Frame (recibido por parámetro) mediante
setSize() y por último se muestra el Frame que ya tiene en su interior la applet
(setVisible()).
Cuando se cierra la ventana, el OyenteLinea se encarga de cerrar la applet, mediante
stop() y destroy(), y de finalizar la aplicación mediante System.exit().
E. Creación de una aplicación que utilice la applet (Swing)
Esta misma aplicación se puede crear utilizando Swing con solo cambiar las siguientes
cosas:
1. Se ha de incluir la biblioteca de Swing:
import javax.swing.*;
2. Se han de cambiar los nombres de la clase Frame de AWT por la clase JFrame de
Swing.
3. Se crea un contentPane mediante un objeto JPanel, justo antes de llamar al oyente:
setContentPane( new JPanel() );
4. Para añadir la applet se ha de añadir al contentPane:
getContentPane().add( unaApplet );
*/
class MiClase {
La documentación que genera es del mismo estilo que la documentación que se obtiene
con el JDK.
Las etiquetas, que se indican con una arroba (@), aparecerán resaltadas en la
documentación generada.
Su sintaxis es:
javadoc Opciones NombreArchivo
• Opciones: Opciones sobre qué documentación ha de ser generada.
• NombreArchivo: Paquete o archivo de código fuente Java, del que generar
documentación.
i.) Applets de demostración
El JDK incluye una serie de applets de demostración, con su código fuente al completo.
j.) Código fuente la API
El código fuente de la API se instala de forma automática, cuando se descomprime el
JDK, aunque permanece en formato comprimido en un archivo llamado "scr.zip"
localizado en el directorio Java que se creó durante la instalación.
C. Uso del JDK
Ya se han visto las diferentes partes de que está compuesto el JDK, pero para el
desarrollo de una aplicación final Java (ya sea una aplicación o una applet), deberemos
utilizar las diferentes herramientas que nos proporciona el JDK en un orden
determinado.
En el siguiente diagrama podemos ver la sucesión de pasos para generar un programa
final Java:
static {
System.loadLibrary("LibHola");
new HolaNativo().diHola();
}
}
El método nativo diHola() no tiene cuerpo porque será añadido mediante una biblioteca
nativa denominada LibHola. Dicha biblioteca nativa es cargada mediante la sentencia
loadLibrary(), sentencia que ha sido incluida como static para que sea ejecutada cada
vez que se cree una instancia (objeto) de esta clase.
El programa principal tan sólo instancia un objeto de esta clase y utiliza el método
nativo que imprime la cadena de "¡Hola Mundo!!!".
b.) Compilación del programa Java
Ahora ya es posible compilar la clase Java HolaNativo que fue creada mediante la
sentencia (utilizando el JDK):
javac HolaNativo.java
c.) Creación de un fichero de cabecera nativo (.h)
Un fichero de cabecera nativo es un fichero que habitualmente tiene la extensión ".h".
En un fichero de este tipo se definen en C/C++ las interfaces públicas (clases, métodos
o funciones, variables globales, constantes...).
La herramienta javah incluida en el JDK es capaz de crear automáticamente un fichero
de cabecera para métodos nativos Java, con sólo invocarla indicando el nombre de la
clase de la que extraer las cabeceras nativas:
javah HolaNativo
Esta operación crea un fichero HolaNativo.h que será útil para crear los métodos
nativos. Hay dos líneas importantes dentro de este fichero:
#include <jni.h>
JNIEXPORT void JNICALL
Java_HolaNativo_diHola(JNIEnv*,jobject);
La primera línea importa una biblioteca JNI que valdrá a C/C++ para saber cómo crear
los métodos nativos.
La segunda línea corresponde al método nativo que definimos.
Los métodos nativos suelen denominarse siempre como Java_Paquete_Clase_Metodo()
aunque en este caso al no haber paquete esta parte se ha omitido.
Así mismo los métodos nativos reciben como parámetros JNIEnv* y jobject que
permitirán al método nativo comunicarse con su entorno.
d.) Escritura de los métodos nativos
Se ha de crear un fichero fuente nativo, en el que se defina el cuerpo de la función que
actuará como método nativo. Este fichero lo denominaremos HolaNativo.c:
#include <jni.h>
#include "HolaNativo.h"
#include <stdio.h>
volatile while
Tipos de comentarios:
Bloques de código:
{ // conjunto de sentencias
}
Separadores Java:
{ } , : ;
Propuestas de estilo de nombres de identificadores:
• Las clases: Clase o MiClase.
• Los métodos: metodo() o metodoLargo().
• Las variables: altura o alturaMedia.
• Las constantes: CONSTATE o CONSTANTE_LARGA.
• Los paquetes: java.paquete.subpaquete.
B. Tipos de datos
Vectores:
int vectorNumeros[]=new int[numero];
Cadenas Constates:
String nombreBonito = "Amelia";
Cadenas Variables:
StringBuffer cadenaVariable = "Cambiante";
C. Operadores
Operadores Unarios:
! ! op op es falso
>> op1 >> op2 Desplaza los bits de op1 a la derecha op2 veces
<< op1 << op2 Desplaza los bits de op1 a la izquierda op2 veces
| op1 | op2 OR
~ ~op2 Complemento
Operador terciario:
expresion ? sentencia_si : sentencia_si_no
Precedencia de operadores:
Multiplicación */%
Suma +-
Desplazamiento <<
Igualdad == !=
OR a nivel de bit ^
OR lógico ||
Condicional ?:
D. Estructuras de control
Toma de decisión (if-else y switch):
if ( condición ) {
else {
switch ( expresionMultivalor ) {
sentencias;
};
do {
sentencias;
} while ( expresiónBooleana );
for(inicio; condicion_continuacion;
sentencia_actualizacion) {
sentencias;
Sentencias de saltos:
etiquetaSentencia: sentenciaEtiquetada
break nombreEtiqueta; // Sale del último bucle
continue; // Hace otra pasada al último bucle
return valor; // Sale del método devolviendo valor
E. Clases
Definición de clase:
acceso class NombreDeClase herencia{
// . . .
cuerpo_del_método1;
claseComponente referenciaAObjetoComponente.
}
G. Métodos
Referencias válidas en los métodos:
• this: Referencia al objeto actual.
• super: Referencia a la clase padre en el árbol de herencia.
Modificadores permitidos:
• Acceso: public private o protected. Igual que para los atributos.
• abstract: Método abstractos, sin cuerpo. Sólo se permiten en clases abstractas.
• final: No se puede sobreescribir el método.
• static: Método de la clase (no de los objetos).
• native: Método implementado con métodos nativos (específicos de una
plataforma).
• synchronized: Solamente permite un hilo de ejecución.
Sobrecarga del método: Varias implementaciones en función de los parámetros.
Sobreescritura del método: Un cuerpo en cada nivel de herencia.
H. Objetos
Instanciación:
NombreDeClase referenciaAObjeto = new NombreDeClase();
Acceso al objeto:
referenciaAObjeto.método( parámetros );
referenciaAObjeto.atributo;
Destrucción: Cuando la referencia a objeto sale de ámbito en el programa.
I. Interfaces
Declaración de una interfaz:
interface MiInterfaz {
Implementación de interfaces:
class ImplementaInterfaz implements MiInterfaz{
int m=CONSTANTE;
int metodoAbstracto( int p ){ return ( p*m ); }
Double double
Float float
Long long
Character char
Boolean boolean
J. Paquetes
Creación de un paquete (primera sentencia de un fichero fuente):
package NombrePaquete;
Importación de un paquete o parte de él:
import Paquete.Subpaquete1.Subpaquete2.Clase1;
Paquete.Subpaquetes1.Subpaquete2.Clase_o_Interfaz.elemento
Visibilidad en los paquetes:
En la misma clase Sí Sí Sí Sí
En una clase
No Sí Sí Sí
en el mismo paquete
throw MiException:
} catch( tipo_de_excepcion e) {
} catch( tipo_de_excepcion_mas_general e)
} finally {
L. Threads
Creación:
1. Para crear un thread, se ha de implementar una clase, extendiendo la clase base
Runnable, y crear un objeto de la clase Thread.
2. Este objeto representará un nuevo hilo de control, que será accionado cuando
invoquemos al método start() del thread.
3. En ese momento este hilo se activará, ejecutando (si el planificador de hilos
considera que es el momento), el método run() de la clase en que todo esto
suceda.
Sincronización de procesos:
1. Durante la ejecución de un programa, muchas veces varios procesos han de
realizar tareas de una forma sincronizada, actuando en un determinado orden.
2. Para ello se han de declarar métodos como syncronized.
3. Mediante la utilización de excepciones, y de las funciones wait() y notifiy(),
respectivamente esperarán a que otro proceso acabe antes de continuar su
ejecución.
GLOSARIO
Abstract Windowing Toolkit (AWT).- Biblioteca de módulos pera representar
interfaces gráficos provisto por Sun en la API de Java.
Administrador de Seguridad.- Parte de la máquina virtual Java responsable de velar
por el cumplimiento de las políticas y reglas de seguridad.
Ámbito.- Parte de un programa en el que es válida una referencia a una variable.
American Standard Code for Information Interchange (ASCII).- Sistema de
codificación que convierte caracteres a números en el rango de 0 a 127. Es una parte del
código ANSI que se amplía hasta los 257 caracteres.
Análisis.- Proceso de conocer los requerimientos de software que tienen el cliente y el
usuario final.
API.- Application Programming Interface.
Aplicación.- Programa informático, que se ejecuta sin necesidad de otro programa
Applet.- Programa informático que se ejecuta necesitando de otro programa,
normalmente un navegador.
Application Programming Interface (API).- Conjunto de paquetes y clases Java,
incluidos en el JDK que utilizan los programadores Java para realizar sus aplicaciones.
Árbol.- Estructura de datos, grafo no cíclico, con forma de árbol (nodos padres e hijos).
Argumentos.- Parámetros.
Array.- Vector.
ASCII.- American Standard Code for Information Interchange.
AWT.- Abstract Windowing Toolkit.
BDK.- Beans Developer Kit.
Beans Developer Kit (BDK).- Conjunto de herramientas para desarrollar JavaBeans.
Bit.- Unidad mínima de información digital que puede tomar los valores lógicos de 0 o
de 1.
Bloque.- Código localizado entre corchetes.
Boolean.- Tipo de datos bi-estado, que puede tomar valor de cierto (true) o falso (false).
Byte.- Secuencia de 8 bits.
Cadena.- Secuencia de caracteres.
Carácter.- Símbolo que representa información, o la codificación en una computadora.
Normalmente letras de alfabeto, números o signos ASCII.
Cargador de clases.- Parte del JRE de Java responsable de encontrar archivos de clase
y cargarlos en la máquina virtual Java.
Casting.- Moldeado.
CGI.- Common Gateway Interfaz.
Clase.- Unidad fundamental de programación en Java, que sirve como plantilla para la
creación de objetos. Una clase define datos y métodos y es la unidad de organización
básica de un programa Java.
Common Gateway Interfaz (CGI).- Es un lenguaje de programación que permite
dotar a las páginas Web de interactividad, construyendo una página Web
correspondiente a un enlace de hipertexto en el mismo momento en que se hace "clic"
sobre el enlace. Los script cgi pueden estar escritos en cualquier lenguaje de
programación.
Common Object Requeset Broker Architecture (CORBA).- Estándar para la
conexión entre objetos distribuidos, aunque esté codificados en distintos lenguajes.
Compilador.- Programa de software que traduce código fuente en un lenguaje de
programación legible por una persona a código máquina interpretable por un ordenador.
Constante.- Valor utilizado en un programa de computadoras con la garantía de no
cambiar en tiempo de ejecución. La garantía es a menudo reforzada por el compilador.
En Java las constantes se declaran como static final.
Constructor.- Método que tiene el mismo nombre que la clase que inicia. Toma cero o
más parámetros y proporciona unos datos u operaciones iniciales dentro de una clase,
que no se pueden expresar como una simple asignación.
Contenedor.- En diseño de interfaces de usuario, es un objeto que contiene los
componentes (como botones, barras de deslizamiento y campos de texto).
Conversión de tipos de datos.- Modificación de una expresión de un tipo de datos a
otro.
CORBA.- Common Object Requeset Broker Architecture.
Entero.- Un número entero, sin parte decimal, positivo o negativo.
Estructura de datos.- Una construcción de software (en memoria o en disco duro) que
contiene datos y las relaciones lógicas entre ellos.
Evento.- Un mensaje que significa n incidente importante, normalmente desde fuera del
entorno de software.
Excepción.- Un evento que ocurre durante la ejecución de un programa que interrumpe
el flujo normal de las instrucciones.
Flujo.- Stream.
Graphical User Inteface (GUI).- Interfaz gráfica de usuario.
Hardware.- El aspecto físico de un sistema de computadora, como el procesador, disco
duro e impresora.
Herencia múltiple.- La práctica (permitida en lenguajes como C++ pero no en Java) de
derivar una clase de más de una clase base.
Herencia.- Mecanismo encargado de relacionar clases entre sí de una manera
jerárquica. En Java, sólo existe herencia simple.
Hilo.- Thread.
HTML (HyperText Markup Languaje).- Lenguaje que se utiliza para crear páginas
Web. Los programas de navegación de la Web muestran estas páginas de acuerdo con
un esquema de representación definido por el programa de navegación.
IDE.- Integral Development Environment.
IDL.- Java Interface Definition Language.
Ingeniería del software.- Rama de la ingeniería concerniente con el análisis, diseño,
implementación, prueba, y mantenimiento de programas de computadoras.
Instancia.- Objeto de software construido desde una clase. Por ejemplo, puede tener
una clase avión, pero una flota de quince instancias de avión.
Integral Development Enviroment (IDE).- Una herramienta de desarrollo visual en la
que un programa puede ser construido, ejecutado y depurado.
Interbloqueo.- Condición en la que dos o más entidades de software se bloquean
mutuamente, cada una esperando los recursos que está utilizando la otra.
Interface Definition Language (IDL).- Herramienta mediante la cual los objetos
pueden invocar métodos de otros objetos que se encuentren en máquinas remotas,
mediante CORBA.
Interfaz gráfica de usuario (GUI).- Una interfaz entre la máquina y el hombre como el
Windows de Microsoft, el Mac OS, o el Sistema X Windows, que depende de pantallas
de alta resolución, un recurso gráfico de puntero como un ratón y una colección de
controles en pantalla (denominados Widgets) que el usuario puede manejar
directamente.
Interfaz.- Mecanismo Java para decirle al compilador que un conjunto de métodos
serán definidos en futuras clases. (Esas clases estarán definidas para implementar la
interfaz).
Java 2D.- Paquete que permite a los desarrolladores incorporar texto, imágenes y
gráficos en dos dimensiones de gran calidad.
Java 3D.- Conjunto de clases para crear aplicaciones y applets con elementos en tres
dimensiones. Es parte del JMF.
Java DataBase Connectivity (JDBC).- Lenguaje estándar de Java para interactuar con
bases de datos, similar al SQL. Es independiente no sólo de la plataforma sino también
de la base de datos con que interactúe. Desde la versión 1.2 del JDK se permite
interactuar con ODBC.
Java Developer Connection (JDC).- Conexión de desarrollo en la que se publican las
versiones beta de las biliotecas de Java que se están desarrollando.
Java Foundation Classes (JFC).- Conjunto de componentes y características para
construir programas con interfaces gráficas.
Java Media Framework (JMF).- Protocolo de transmisión de datos para la
reproducción multimedia (vídeo y sonido).
Java Native Invocation (JNI).- Capacidad de Java para ejecutar código nativo, es
decir, código compilado al lenguaje máquina de un determinado ordenador. Permite a la
Máquina Virtual Java (JVM) interactuar con programas o bibliotecas escritos en otros
lenguajes (C/C++, ensamblador...). No se puede utilizar en applets, pues viola las
directrices de seguridad.
Java Runtime Environment (JRE).- Software suministrado por Sun que permite a los
programas de Java ejecutarse en una máquina de usuario. El JRE incluye la Máquina
Virtual Java (JVM).
JRE.- Java Runtime Environment.
JVM.- Java Virtual Machine.
Java Virtual Machine (JVM).- El intérprete de Java que ejecuta los códigos de byte en
una plataforma particular.
JavaBeans.- Paquete que permite escribir componentes software Java, que se puedan
incorporar gráficamente a otros componentes.
JDBC.- Java DataBase Connectivity.
JDC.- Java Developer Connection.
JFC.- Java Foundation Classes.
JMF.- Java Media Framewok
JNI.- Java Native Invocation.
JVM.- Java Virtual Machine.
Llamada por referencia.- Una forma de transferir parámetros a una subrutina en la que
se pasa un puntero o referencia a un elemento, de esta forma, la subrutina puede leer y
cambiar el valor del elemento referenciado.
Llamada por valor.- Una forma de transferir parámetros a una subrutina en la que se
pasa la copia del elemento; las modificaciones de la copia no afectan al elemento
original.
Método.- Conjunto de sentencias que operan sobre los datos de la clase para manipular
su estado.
Miniaplicación.- Applet.
Modelo.- En diseño orientado a objetos, una representación del mundo real en unas
abstracciones de software denominadas clases y la relación entre ellas.
Moldeado.- Suplantación del tipo de un objeto o variable por otro nuevo tipo.
Multiproceso.- En sistemas operativos, la habilidad de efectuar dos o más programas
independientes, comúnmente en un procesador solo (a través de Multitarea).
Navegador Web.- Software que permite al usuario conectarse a un servidor de Web
utilizando Hypertext Transfer Protocol (HTTP). Microsoft Internet Explorer, Netscape
Navigator, HotJava de Sun, son populares navegadores de Web.
Navegador.- Navegador Web.
null.- Valor de Java que significa vacío.
Object DataBase Conectivity (ODBC). Lenguaje estándar de Microsoft; que utiliza un
driver del fabricante de una base de datos, para interactuar con ella, más orientado a
C/C++ que a Java.
ODBC.- Object DataBase Conectivity.
Paquete.- Nombre de Java para una biblioteca de clases.
Parámetros formales.- Nombres utilizados dentro de una subrutina por sus parámetros.
Parámetros.- Valores u objetos pasados entre una subrutina y la rutina de llamada.
Plug-in.- Un programa de una plataforma específica diseñado para ser llamado por un
navegador Web. Utilizado con frecuencia para mostrar información que el mismo
navegador no puede mostrar.
Poliforfismo.- En diseño orientado a objetos, la habilidad de utilizar una clase derivada
en lugar de su clase base. Por ejemplo, un programador puede escribir un método
expresarse() para la clase Mamífero. Un Perro, una Vaca y un Gato se derivan de
Mamífero, y todos pueden expresarse(), aunque sus voces sean bastantes diferentes.
Proceso.- Instancia de un programa ejecutable. Por ejemplo, si inicia dos copias de un
intérprete de Java, tiene dos procesos de la máquina virtual de Java ejecutándose en su
computadora.
Seudocódigo.- Documentación de diseño que describe el trabajo de un programa en
inglés estructurado (o en otro lenguaje) en lugar de un lenguaje de computadora.
Recolector de basura.- En Java, el mecanismo por el cual se recobra y libera la
memoria asociada con objetos no utilizados.
Remote Method Invocation (RMI).- Herramienta que incorpora métodos Java ara
localizar objetos remotos, comunicarse con ellos e incluso enviar objetos como
parámetros de un objeto a otro.
RMI.- Remote Method Invocation.
Secure Sockets Layer (SSL).- Sistema para la creación de conexiones seguras en red.
Servlets.- Módulos que permiten sustituir o utilizar el lenguaje Java en lugar de
programas CGI.
Shell.- Intérprete de órdenes de un sistema operativo.
Sistema operativo.- Software responsable de asignar a los usuarios los recursos de
sistemas de computadoras (incluyendo procesos). UNIX, Windows, NT y Mac OS, son
ejemplos de sistemas operativos.
SQL.- Structured Query Language.
SSL.- Secure Sockets Layer.
Estático.- En diseño orientado a objetos, representa la pertenencia a la clase, en vez de a
una instancia. Es un espacio compartido por todas las instancias de una clase.
Stream.- Flujo de datos. Por ejemplo las entradas y salidas de un programa.
String.- Objeto Java estandarizado en el lenguaje, que representa una cadena de
caracteres.
Structured Query Language (SQL).- Lenguaje para realizar consultas a Bases de
Datos relacionales.
Subclase.- Clase descendiente de otra clase de la que hereda métodos y variables.
Superclase.- Clase de la cual heredan sus métodos y variables otras clases denominadas
subclases.
Swing.- Paquete que permite incorporar elementos gráficos en las aplicaciones, de una
manera más potente que con el AWT. Aparece en la versión 1.2 del JDK. Es no de los
componentes que están incluidos en las Java Fundation Classes, o JFC.
Thread.- Un "proceso ligero" que puede ser arrancado y utilizado más rápidamente que
por un fork o spawn. Véase también: fork, spawn y Proceso.
Tiempo de vida.- El número de líneas sobre las que una variable es activa, esto es, el
número de líneas entre la primera y la última referencia a la variable.
Tipo primitivo.- En Java, un tipo de dato que no es un objeto. Los tipos primitivos
incluyen caracteres, enteros, número de coma flotante y booleanos.
UML.- Unified Modeling Language.
Unicode.- Conjunto de caracteres de 16 bits, en lugar de los 8 que soportaba ASCII. Así
se pueden representar la mayor parte de los lenguajes del mundo.
Unified Modeling Language (UML).- Notación estándar de facto utilizada en el
análisis y diseño orientado a objetos, basado en el trabajo de Grady Booch, James
Rumbaugh, e Ivar Jacobson.
Vector.- Estructura de datos que coloca un tipo de datos en celdas continuas.
Verificador de código de byte.- Rutinas en la máquina virtual de Java, que aseguran
que las instrucciones en el archivo de clase no violan ciertas restricciones de seguridad.
Anterior - Índice
BIBLIOGRAFÍA
Se ha dividido este apartado en diversos puntos, intentando explicar qué referencias
bibliográficas han sido utilizadas en mayor o menor medida para realizar este tutorial.
En cada reseña bibliográfica se indican el número de páginas que tiene, y un comentario
personal indicando su utilidad para una mayor profundización en Java.
A. Bibliografía consultada para la actual versión:
• [Arnold y Gosling, 1997] Ken Arnold y James Gosling. Addison-
Wesley/Domo. "El lenguaje de Programación Java". Wesley Iberoamericana.
1997. 334 páginas. (Muy básico, escrito por el desarrollador del lenguaje).
• [Eckel, 1997] Bruce Eckel. "Hands -on Java Seminar". Presindent MindView
Inc. 1997. 577 páginas. (Tutorial completo en Inglés en formato PDF).
• [García et al., 1999]. Javier Garciá de Jalón, José Ignacio Rodríguez, Iñigo
Mingo, Aitor Imaz, Alfonso Brazález, Alberto Larzabal, Jesús Calleja y Jon
García. "Aprenda Java como si estuviera en primero". Universidad de Navarra.
1999. 140 páginas. (Tutorial muy básico, en el que se trata la potencia de Java,
pero sin profundizar en ningún tema en particular).
• [García, 1997] Francisco José García Peñalvo. "Apuntes de teoría de la
asignatura Programación Avanzada del tercer curso de Ingeniería Técnica en
Informática de Gestión". Universidad de Burgos. 1997. 216 páginas. (Comentan
la teoría de la programación orientación al objeto. Han sido resumidos para
dar una visión de la programación orientada a objeto en el apartado I.1).
• [Johnson, 1996] Jeff Johnson. "Coding Standards for C, C++, and Java".
Vision 2000 CCS Package and Application Team. 1996. 14 páginas. (Consejos
para el formato de los fuentes Java, C y C++).
• [Morgan, 1999] Mike Morgan. "Descubre Java 1.2". Prentice Hall. 1999. 675
páginas. (Sin duda muy interesante, sobre todo por su actualidad al tratar con
Java 2, y por su extensión al tratar todas las bibliotecas de Java).
• [Naughton, 1996] Patrick Naughton. "Manual de Java". Mc. Graw Hill 1996.
395 páginas. (Introduce todos los aspectos de la programación básica en Java).
• [Rojo, 1998] Ignacio Rojo Fraile. "Comparativa de herramientas Java".
Artículo de la revista Solo Programadores nº49. Tower. Octubre 1998.
(Compara 5 IDEs Java).
• [Sanz, 1998] Javier Sanz Alamillo. "Novedades y cambios con Java 2".
Artículo de la revista Solo Programadores nº55. Tower. Marzo 1999. (Buen
resumen de los cambios que han surgido en el JDK 1.2).
• [Sun, 1998] Sun Microsystems Inc. "JDK 1.2 Documentation". www.sun.com.
1997. (Documentación de la API de Java del JDK).
• [van Hoff et al., 1996] Arthur van Hoff, Sami Shaioi y Orca Starbuck.
"Hooked on Java". Addison-Weslet. 1996. (Todo lo que hace falta saber para
crear applets, con muchos ejemplos. En inglés).
• [Zolli, 1997] Andrew Zolli. "La biblia de Java". Anaya multimedia. 1997. 814
páginas. (Completo en lo a que biliotecas del JDK 1.1 se refiere).
B. Bibliografía adicional o citada en la actual versión:
• [Piattini et al., 1996] Mario G. Piattini, José A. Calvo-Manzano, Joaquín
Cervera y Luis Fernández. "Análisis y diseño detallado de Aplicaciones
informáticas de gestión". Ra-Ma. 1996.
• [Rambaugh et al., 1998] J. Rambaugh J., M. Blaha, W. Premerlani, F. Eddy
y W. Lorensen. "Modelado y Diseño Orientados a Objetos. Metodología
OMT". Prentice Hall, 2º reimpresión. 1998.
• [Rational, 1997] Rational Software Corporation. "The Unified Modeling
Language Documentation Set 1.1". www.rational.com. Septiembre de 1997.
• [Rifflet, 1998] Jean-Marie Rifflet "Comunicaciones en UNIX". McGraw Hill.
1998.
C. Bibliografía adicional que se utilizó en la versión 1.0
• [Cortés et al.,1996] José Luis Cortés, Nuria González, Virginia Pérez, Paqui
Villena y Ana Rosa Freire. "Java, el lenguaje de programación de Internet".
Data Becker 1996.
• [Cuenca, 1996] Pedro Manuel Cuenca Jiménez. "Programación en Java para
Internet". Anaya Multimedia. 1996.
• [Cuenca, 1997] Pedro Manuel Cuenca Jiménez,. "Programación en Java".
Ediciones Anaya Multimedia. 1997.
• [Framiñán, 1997] José Manuel Framiñán Torres. "Manual Imprescindible de
Java". Ediciones Anaya Multimedia. 1997.
• [Lalani, 1997] Suleiman 'Sam' Lalani. "Java, biblioteca del programador".
Ediciones McGraw Hill. 1997.
• [Froufe, 1997] Agustín Froufe. "Tutorial de Java". Facultad de Informática de
Sevilla. 1997. http://www.fie.us.es/info/internet/JAVA/.
D. Direcciones de interés
Se recomienda suscribirse a la lista de correo de Sun sobre Java, cuya dirección es:
javanews@US.IBM.COM
Anterior - Índice
Guía de Iniciación al
Lenguaje JAVA
RESUMEN
Este trabajo corresponde a una guía que sirva de iniciación a la programación en el
lenguaje Java. En él se tratan los diversos aspectos básicos que comprenden el
aprendizaje de un lenguaje de programación, así como una breve noción de la
Programación Orientada al Objeto en la que Java se basa.
Así mismo se incluyen comparativas con otros lenguajes de programación (especial
hincapié en C++), y se tratan con un poco más de profundidad bibliotecas gráficas
como AWT y Swing.
Se comentan también aspectos relacionados con Internet, como son las bibliotecas de
Sockets y las famosas applets de Java.
DOCUMENTOS
Los siguientes documentos son transferibles vía FTP:
Guía en formato PDF: java20.pdf (541Kb).
Guía en HTML comprimida: javahtml.zip (285Kb).
Applets de ejemplo comentados en el tutorial: applets.zip (247Kb).
Apicaciones de ejemplo comentados en el tutorial: programas.zip (40Kb).
Siguiente