P. 1
Java - Manual de Java - Spanish

Java - Manual de Java - Spanish

|Views: 280|Likes:

More info:

Published by: Fabián Silva Alvarado on Dec 26, 2010
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

07/31/2013

pdf

text

original

Sections

  • Tema 6 COMENTARIOS
  • Tema 11 EXCEPCIONES

TEMA 1: INTRODUCCIÓN A LA PLATAFORMA JAVA_____________________________1

TEMA 2: CONCEPTOS BÁSICOS DE LA PROGRAMACIÓN ORIENTADA A OBJETOS___11

TEMA 3: PREPARANDO EL ENTORNO________________________________________19

TEMA 4: PALABRAS CLAVE. TIPOS DE DATOS. OPERADORES. IDENTIFICADORES.

VARIABLES CONSTANTES LITERALES_______________________________31

TEMA 5: CADENAS Y ARRAYS______________________________________________59

TEMA 6: COMENTARIOS___________________________________________________67

TEMA 7: ESTRUCTURAS DE CONTROL DE FLUJO______________________________75

TEMA 8: OBJETOS: CREACIÓN, USO Y ELIMINACIÓN___________________________99

TEMA 9: CLASES. HERENCIA Y POLIMORFISMO______________________________111

TEMA 10: CLASES ABSTRACTAS E INTERFACES_____________________________131

TEMA 11:. EXCEPCIONES_________________________________________________141

TEMA 12. PAQUETES: CREACIÓN Y UTILIZACIÓN. LOS PAQUETES

SUMINISTRADOS CON JAVA_____________________________________151

TEMA 13. LA CLASE SYSTEM. LOS CANALES DE ENTRADA Y SALIDA ESTÁNDAR__167

GLOSARIO_____________________________________________________________191

- 1 -

1.1. ¿Qué es Java?_______________________________________3

1.2. El lenguaje Java_____________________________________4

1.3. La arquitectura de la máquina Java______________________6

1.4. El modelo de carga___________________________________6

1.5. El formato de ficheros de clases_________________________7

1.6. El entorno de aplicaciones_____________________________7

1.7. La especificación e implementación______________________8

1.8. Dónde se utiliza Java_________________________________8

1.9. ¿Podemos hacerlo todo con Java?______________________9

Tema 1

INTRODUCCIÓN A LA
PLAFORMA

JAVA

- 3 -

1.1. ¿QUÉ ES JAVA?

Cuando oímos hablar de Java lo primero que pensamos es en un lenguaje de programación, si bien es
cierto que dicha afirmación no se ajusta del todo a la realidad. Cuando nos preguntan acerca de qué es
Java, podríamos responder que se trata de un lenguaje, una arquitectura de máquina, un modelo de
carga, un formato de ficheros, un entorno de aplicaciones, una especificación y una implementación.

Existen muchas versiones acerca de los orígenes de Java, pero la más extendida es la que lo muestra
como lenguaje de pequeños electrodomésticos.

Hace algunos años, Sun Microsystems decidió introducirse en el mercado de la electrónica de consumo y
desarrollar programas para pequeños dispositivos electrónicos. James Gosling, el miembro del equipo
con más experiencia en lenguajes de programación, decidió que las ventajas de eficiencia que aportaba
C o C++ no compensaban el coste que suponían los desarrollos. Además, dichos lenguajes deben ser
compilados para un chip concreto, de modo que si éste cambia ha de compilarse de nuevo, lo cual era un
inconveniente para un mercado tan cambiante.

James Gosling había estado desarrollando en su tiempo libre un lenguaje con una sintaxis similar a la de
C++ y en el que intentaba remediar las deficiencias que observaba en este último. Este lenguaje fue
bautizado con el nombre de Oak y decidieron mejorar sus características para, posteriormente, utilizarlo.

Este proyecto no tuvo el éxito esperado y quedó relegado al olvido durante algún tiempo. Más adelante
Bill Joy, cofundador de Sun, vio en Oak el instrumento adecuado a través de Internet para disputar a
Microsoft su primicia absoluta en el terreno del software. Tras un cambio de nombre y modificaciones de
diseño, Java fue presentado en agosto de 1995.

En respuesta a la pregunta planteada al principio, podemos afirmar que Java es un verdadero lenguaje
orientado a objetos. Incorpora algunos de los conceptos más modernos y potentes sobre el diseño de
lenguajes de programación. Se diseño procurando ocultar las complejidades que en muchos otros
lenguajes es visible, procurando obtener, de esta forma, un mayor rendimiento de los programadores. A
pesar de que Java aplica estrictamente muchas reglas en tiempo de compilación, también posee
características que le permiten escribir código muy dinámico.

- 4 -

Java es un lenguaje compilado pero, al contrario que con la mayoría de los otros lenguajes compilados,
su código no es específico de la máquina ni del sistema operativo. Cualquier sistema con una máquina
virtual de Java (JVM, Java Virtual Machine) puede ejecutar el mismo Java compilado.

Entre las capacidades y características que incluye el lenguaje, tenemos el desarrollo intrínseco con
múltiples hebras, la gestión de excepciones, la recolección de basura, una colección de clases muy
completa para el desarrollo de aplicaciones de bases de datos, de gráficos o de comunicaciones, y
muchas otras más que han originado la gran aceptación de la industria informática por él.

Los programas Java pueden ser de muchos tipos, pero el más conocido es el de los applets. Un applet
es código Java que se descarga automáticamente de la web y que se ejecuta dentro del explorador web,
en el ordenador del usuario. Este tipo de programas no requiere instalación, posibilita interfaces de
usuario muy ricas y lleva asociado un estrictos mecanismos de seguridad.

Pero Java también puede usarse para desarrollar aplicaciones completas. Estas aplicaciones se instalan
los sistemas concretos y no tienen las restricciones de los applets. Con ellas se puede realizar
prácticamente cualquier tarea que pueda hacerse con otros lenguajes de programación, desde simples
aplicaciones locales hasta complejas aplicaciones distribuidas.

Por otro lado, es preciso mencionar que Java tiene un fértil campo en las aplicaciones con tecnología de
servidor. De hecho, actualmente es posible desarrollar aplicaciones web, componentes distribuidos y
servicios web.

Antes mencionamos que Java no es sólo un lenguaje, sino que va más allá. Eso es lo que vamos a
explicar a continuación.

1.2. EL LENGUAJE JAVA

Inicialmente se planteó como una alternativa al lenguaje C++ y uno de sus objetivos era mejorar los
déficits de éste último. Entre los remedios que plantea Java podemos citar:

• Robustecimiento de la programación orientada a objetos y eliminación de todas las

características no orientadas a objetos.

- 5 -

• Eliminación de la posibilidad de manipular directamente punteros a memoria.

• Eliminación de la confusa gestión de memoria por parte de los diseñadores de aplicaciones.

• Reforzamiento de la seguridad de los tipos.

• Realización de comprobaciones en tiempo de ejecución para problemas comunes como moldeos

ilegales y referencias a objetos nulos.
• Soporte para programación multihilo directamente en el lenguaje.

• Mejora en la gestión de excepciones (manejo de errores).

Como lenguaje de programación, podemos citar de él las siguientes características:

• Simple. Ofrece la funcionalidad de un lenguaje potente pero sin las características menos

usadas y más confusas de éstos. El ejemplo más claro puede ser el recolector de basura, que
evita que andemos preocupándonos de liberar memoria. Otro ejemplo podría ser la supresión de
los punteros.
• Orientado a objetos. Soporta las tres características básicas de la orientación a objetos:

encapsulación, herencia y polimorfismo.
• Distribuido. Proporciona las librerías y herramientas necesarias para que las aplicaciones

puedan ser distribuidas. Se ha desarrollado con extensas capacidades de interconexión a red y
soporta varios protocolos de red.
• Robusto. Realiza variadas comprobaciones tanto en tiempo de compilación como de ejecución.

Entre ellas podemos mencionar la comprobación de tipos y la comprobación de límites de arrays.

• Portable. Esto no se refiere a la independencia de la plataforma, si no a la portabilidad en cuanto

a desarrollo. Por ejemplo, los enteros son siempre enteros de 32 bits en complemento a 2, con
independencia de la plataforma.

• Multiplataforma. Como mencionamos antes, no es necesario recompilar las aplicaciones Java

para los distintos sistemas en que van a ser explotadas.
• Multihilo. Permite múltiples hilos de ejecución, es decir, muchas actividades simultáneas dentro

del mismo programa. Las ventajas de esto son un mejor rendimiento interactivo (el usuario no
percibe tanto la ocupación de la máquina) y un mejor comportamiento en tiempo real (aunque
sea algo muy limitado por el sistema operativo).

• Dinámico. Cuando una aplicación se lanza, no se cargan todas las librerías que requiere, sino

que la carga es bajo demanda. Las librerías nuevas o actualizadas no paralizarán las
aplicaciones en funcionamiento.

- 6 -

1.3. LA ARQUITECTURA DE LA MÁQUINA JAVA

La especificación Java no sólo describe un lenguaje de alto nivel, también define la máquina a bajo nivel y
el conjunto de instrucciones que es capaz de ejecutar. Podría hacerse una analogía con la máquina de
Código P (P-Code) que se usó en el desarrollo del Pascal en la década de los 80.

La implantación de la arquitectura se ha dejado a la libre elección de los proveedores. Esta arquitectura
bien podría ser un microprocesador Java (hace unos años se desarrollaron algunos), o bien, una máquina
virtual (software). Actualmente, existen máquinas virtuales para la mayoría de los entornos existentes
(Windows, MacOS, Linux, los diversos UNIX).

Además de describir el motor de ejecución, la especificación describe otros comportamientos como el
arranque, la carga y el apagado.

1.4. EL MODELO DE CARGA

El modelo de carga Java lo hace un lenguaje único. La carga de las clases tiene lugar dinámicamente
durante la ejecución del programa. Con esto se rompe la dinámica tradicional de la compilación,
enlazado, carga y ejecución que todos conocemos y que es requerida para crear y ejecutar programas.

La carga de clases tiene lugar en varios pasos:

• Lectura de los bloques.

• Verificación de que los bloques definen una clase bien estructurada que contiene código Java

bien estructurado.

• Construcción de una estructura de clase global.

• Resolución de las referencias.

• Control de acceso, permitiendo que una aplicación o entorno decida las reglas de acceso para la

carga de la clase.

La carga de clases se produce bajo demanda según se necesite. Este concepto no es nuevo y, de hecho,
lo vemos rutinariamente en las librerías dinámicas, los modelos de objeto (CORBA, COM y otros) y la
capacidad plug-in de algunos productos. Pero lo que sí es nuevo es la total integración de la carga de

- 7 -

clases con el lenguaje y el entorno. Permitir la carga de clases desde fuentes dispares (disco local, web,
dispositivos de red y otros) es un gran adelanto en la programación orientada a objetos, ya que permite
tratar los objetos del código ejecutable con la misma facilidad que antes estaba reservada sólo para los
objetos de datos.

En la siguiente figura se muestra un esquema del funcionamiento del cargador con una clase de ejemplo.

1.5. EL FORMATO DE FICHEROS DE CLASES

Java también define, para el código, un paquete independiente de la plataforma. Este paquete recibe el
nombre de archivo de clases. Estos archivos son generados por un compilador Java por lo que pasan a
estar disponibles para ser ejecutados. Los archivos de clases se encontrarán, normalmente, en sistemas
de ficheros o empaquetados en archivos (ficheros “.zip” o “.jar”) y el sistema de carga de clases de Java
esperará encontrarlos con la extensión “.class”.

1.6. EL ENTORNO DE APLICACIONES

Teniendo en cuenta que las aplicaciones actuales se ejecutan en un entorno proporcionado por librerías y
subsistemas, Java proporciona a las aplicaciones todo el entorno, desde los servicios básicos de
entrada/salida hasta los interfaces de usuario para trabajo en red. Así pues, Java ha ido aportando
entornos cada vez más mejorados a través de sus distintas versiones del JDK (Java Development Kit).

- 8 -

Actualmente, dispone de un entorno de aplicaciones con componentes GUI (Graphic User Interface),
soporte de impresión, métodos de invocación remota, conectividad de bases de datos, gráficos 2D,
soporte “drag & drop”, una API de audio, y un largo etcétera que constituyen un entorno muy completo.

1.7. LA ESPECIFICACIÓN E IMPLEMENTACIÓN

Hemos mencionado varias veces la palabra “especificación”. Java es sobre todo una especificación1

y a
partir de ésta es posible crear cualquier parte de él. Podríamos crear nuestro propio compilador. Es por
ello que diversas corporaciones hayan creado implementaciones, tanto gratuitas como comerciales.

1.8. DÓNDE SE UTILIZA JAVA

Como indicamos al principio de este tema, Java es una plataforma tan virtuosa que ha encontrado
múltiples escenarios en los que asentarse. A continuación vamos a ver una relación de algunos de ellos.

• Aplicaciones Java independientes bajo diversos sistemas operativos: Linux, Windows, MacOS,

diversas modalidades de UNIX, etc.

• Entornos de ejecución de applets proporcionados por los navegadores más populares.

• Servidores web para la generación dinámica de contenidos.

• JavaOS. Sistema operativo de Sun para ordenadores y sistemas de redes.

• En sistemas de gestión de bases de datos como Oracle para soporte de procedimientos

almacenados.
• Cajas de televisión que ejecutan JavaTV.

• Tarjetas inteligentes. Son tarjetas de plástico con un chip y una máquina virtual de Java

completa.

• Controladores integrados en dispositivos como impresoras y cámaras.

• En Joyería. Anillos y relojes, por ejemplo, con una máquina virtual integrada y que se emplean

para identificación, comercio electrónico y criptografía.

1

La especificación Java al completo se puede descargar de la web de Sun Microsystems en la dirección http://java.sun.com.

- 9 -

1.9. ¿PODEMOS HACERLO TODO CON JAVA?

Java es un sueño por muchas y muy variadas razones. Incorpora las tecnologías más interesantes
desarrolladas a lo largo de la historia de la informática como por ejemplo: recolección de basura, código
independiente de la plataforma y carga dinámica de las clases.

Pero este es justamente el problema, es lento. Con el desarrollo de mejoras en las especificaciones Java
se irá paliando esto, pero hay buenas razones para pensar que nunca podrá competir en velocidad con
las aplicaciones nativas compiladas.

Algunos de los problemas que no se pueden manejar actualmente con Java son:

• Problemas críticos de prestaciones. Para ello se requieren aplicaciones nativas ocomponentes

nativos en las aplicaciones Java.

• Los problemas que implican gran cantidad de memoria o requisitos de entrada/salida.

• Problemas específicos de la plataforma. Java logra la independencia de la plataforma y para ello

no aprovecha las características de los lenguajes nativos. Para intentar solventar este problema
existe la librería JNI (Java Native Interface), que permite mezclar Java y código nativo.

• GUI2. Java tiene una GUI pero su rendimiento es inferior al nativo del propio sistema.

Actualmente Java tiene más éxito en entornos no GUI (como servidores).

2 Siglas de Graphical User Interface. Permite a los usuarios navegar e interactuar con las informaciones en la pantalla de su

ordenador utilizando un ratón para señalar, pulsar y desplazar iconos y otros datos de la pantalla, en lugar de escribir palabras y
frases.

- 10 -

RECUERDE

• Java es, sobre todo, una especificación de un lenguaje, una arquitectura de máquina, un modelo

de carga, un formato de ficheros, un entorno de aplicaciones, una especificación y una
implementación.

• El lenguaje java se caracteriza por ser: simple, orientado a objetos, distribuido, robusto, portable,

multiplataforma, multihilo y dinámico.

- 11 -

2.1. Encapsulación______________________________________14

2.2. Herencia___________________________________________14

2.3. Polimorfidmo_______________________________________16

Tema 2

CONCEPTOS BÁSICOS
DE LA PROGRAMACIÓN
ORIENTADA A

OBJETOS

- 13 -

La programación orientada a objetos nació con posterioridad a la programación procedimental. Esta
última toma como unidades organizacionales a los procedimientos (de ahí su nombre), mientras que en la
primera las unidades organizacionales son los objetos. Pero, ¿qué es un objeto?.

En la vida real podemos observar que estamos rodeados de objetos, por ejemplo una mesa, una silla, un
bolígrafo, etc. y todos ellos podrían clasificarse (con mayor o menor detalle) atendiendo a una definición.
Además, sabemos que a pesar de existir muchos tipos de mesas, todas ellas tienen unas características
comunes. En definitiva, es posible concluir que pueden hacerse dos distinciones:

• Por una parte tenemos el concepto de lo que es una mesa.

• Por otra parte tenemos mesas concretas.

Esta idea fue trasladada a la informática y surgieron los conceptos de clase y objeto. Podemos decir que
una clase es un concepto sobre una entidad abstracta que define cómo serán todos los objetos que
existan de ese tipo. Por tanto, un objeto es una concreción mientras que una clase es una abstracción.

Si trasladamos la definición anterior a la jerga técnica informática, podemos decir que una clase es un
prototipo que define las propiedades y los métodos comunes a múltiples objetos de un mismo tipo. Sería
como una plantilla para la creación de objetos. Por su parte, un objeto es un conjunto de propiedades y
métodos capaces de manipular dichas propiedades. No vamos a entrar en los detalles concretos en Java
ya que veremos todo esto en temas posteriores.

Ya hemos mencionado que Java es un lenguaje orientado a objetos, pero ¿qué determina si un lenguaje
es orientado a objetos? La respuesta es relativamente sencilla. Podemos decir que un lenguaje está
orientado a objetos si soporta objetos como una característica fundamental del mismo. Pero, ¿qué
significa soportar objetos? Fundamentalmente consiste en que el lenguaje permita las siguientes
características:

• Encapsulación.

• Herencia.

• Polimorfismo.

- 14 -

2.1. ENCAPSULACIÓN

Hemos mencionado antes que cada objeto es un conjunto de propiedades y métodos, es decir, datos y
programas relacionados entre sí como si estuvieran encerrados en una cápsula. Son inaccesibles e
impiden conocer cómo está distribuida la información dentro de ellos.

Esto implica que las peticiones de información a un objeto deben hacerse mediante mensajes dirigidos a
él. Un mensaje es una simple llamada a un método del objeto con el que se quiere comunicar.

El hecho de ser una cápsula, algo cerrado e inaccesible, favorecerá la depuración de aplicaciones y la
reutilización del código en caso de migrarlo a otros entornos.

Hagamos una comparación con lo que sería la vida real. Cuando montamos en un coche nos limitados a
dar a la llave contacto y el motor arranca. Es muy simple, pero esa simpleza nos la brinda la
encapsulación. La realidad es que ocurren muchas cosas: contacto eléctrico, funcionamiento del motor de
arranque, apertura del paso de combustible, etc. Pero, ¿necesitamos saber realmente lo que ocurre para
hacer uso de él? No, nos basta con saber que para arrancarlo necesitamos introducir la llave en el
contacto y girarla.

2.2. HERENCIA

La herencia es una característica que permite la creación de clases a partir de otras. Esto conlleva tanto
la reutilización del código, como la especialización de las clases.

La reutilización del código viene dada porque podemos definir clases nuevas partiendo de otras ya
existentes. En este caso se heredan sus propiedades y métodos. La especialización de las clases viene
por añadidura ya que, al definir una clase partiendo de otra, lo que estamos es creando una nueva clase
más especializada.

Visto lo anterior podemos ya intuir que las clases pueden organizarse jerárquicamente. Esta jerarquía
viene determinada por el uso realizado de la herencia. Con esta organización empezamos a tener
términos como: clase padre, clase hija, superclase (o clase raíz) y clase final. A continuación vamos a
explicarlos:

- 15 -

• Clase padre o superclase: se dice que una clase es padre de otra cuando sirve como punto de

partida para crear a esta última.
• Clase hija o subclase: es aquella clase que hereda de otra, y es hija con respecto a su clase

padre o su superclase.

• Clase final: toda aquella que no es clase padre de otras.

Para ilustrar todo esto vamos a examinar la siguiente figura:

En la imagen anterior se representa una jerarquía de clases de figuras geométricas. En la cima de la
jerarquía tenemos la clase “Figura”, y es la clase padre de las clases “Circulo” y “Poligono”. La clase
“Circulo” es una clase hija de la clase “Figura” y también es una clase final. La clase “Poligono” es clase
hija de la clase “Figura” y clase padre de las clases “Rectangulo” y “Triangulo”. El resto de relaciones que
faltan serían similares a las ya explicadas.

La herencia puede ser de dos tipos: simple y compuesta. La diferencia entre ambas es que en el caso de
herencia compuesta se permite heredar de más de una clase. En otras palabras, se trata de que una
clase hija pueda tener más de una clase padre.

- 16 -

En la práctica son pocos los lenguajes que permiten herencia múltiple dada la complejidad que supone
soportarla. En el caso de Java no está permitida. Java sólo permite herencia simple pero dispone de un
mecanismo para paliar esta deficiencia, aunque no siempre es suficiente. Estamos hablando de las
interfaces. El lenguaje Java nos permite heredar de una única clase e implementar varias interfaces. En

el tema “Clases abstractas e interfaces” veremos en qué consisten las interfaces y los motivos por los
cuales no siempre pueden sustituir a la herencia múltiple.

2.3. POLIMORFISMO

Consiste en la posibilidad de tener métodos con el mismo nombre en distintas clases. Al hablar de
métodos en distintas clases nos estamos refiriendo a métodos distintos y por tanto con comportamientos
distintos a pesar de que tengan el mismo nombre.

El polimorfismo permite poder enviar un mismo mensaje (recordemos que un mensaje es una invocación
a un método) a objetos de clases diferentes. Estos objetos recibirán el mismo mensaje pero responderán
a él de formas diferentes. Por ejemplo, un mensaje “+” para un objeto entero significaría una suma,
mientras que para un objeto string (cadena de caracteres) significaría la concatenación.

Revisemos el siguiente gráfico:

En él podemos ver una jerarquía de clases en la que todas las clases que la componen tienen un método
llamado “dibujar()”. Todos tienen el mismo nombre pero cada uno de ellos podrá tener una funcionalidad
distinta. En este ejemplo concreto, una posible interpretación podría ser que tenemos dos clases hijas
que redefinen el método “dibujar()” de su clase padre. Probablemente el método “dibujar()” de la clase

- 17 -

padre sea un método abstracto (no se ha implementado, sólo se ha definido) ya que para dibujar un
polígono es necesario saber el tipo de polígono del que se trata. Por tanto, las clases hijas de la clase
“Poligono” se ven obligadas a implementar el método “dibujar()” que será distinto en cada caso. Esto es
un claro ejemplo de polimorfismo.

- 18 -

RECUERDE

• Las entidades claves de la programación orientada a objetos son las clases y los objetos. Las
clases son conceptuales mientras que los objetos son concreciones.

• Las tres características básicas de la programación orientada a objetos son el encapsulamiento,
la herencia y el polimorfismo.

• El encapsulamiento consiste en ocultar la complejidad de una clase e impedir accesos no

permitidos.

• La herencia es la posibilidad crear clases partiendo de otras. Un medio para reutilizar
funcionalidad.

• El polimorfismo permite disponer de métodos con un mismo nombre en distintas clases.

- 19 -

3.1. El entorno de desarrollo______________________________21

3.1.1. El compilador de Java________________________21

3.1.2. El intérprete de Java_________________________22

3.1.3. Accesibilidad al entorno_______________________22

3.2. Un clásico: Hello World!______________________________24

3.3. Convenciones y nomenclatura en la programación Java____28

Tema 3

PREPARANDO EL

ENTORNO

- 21 -

Java es multiplataforma y en este manual no nos vamos a centrar en ningún sistema operativo concreto.
No obstante, para mostrar los ejemplos era necesario elegir alguno y, en este caso, nos hemos
decantado por la línea de comandos del DOS (también llamada símbolo del sistema en las distintas
versiones de Windows) y por la consola de terminal de los sistemas UNIX/Linux.

3.1. EL ENTORNO DE DESARROLLO

Existen muchos entornos que permiten desarrollar código para Java, tanto comerciales como gratuitos.
La compañía creadora de Java, Sun Microsystems, distribuye gratuitamente el Java Development Kit
(JDK). Éste es un conjunto de programas y librerías que permiten desarrollar, compilar y ejecutar
programas en Java. Asimismo, tenemos también una versión reducida del JDK que sólo permite ejecutar
código Java y que recibe el nombre de Java Runtime Environment (JRE).

Existen también los llamados entornos de desarrollo integrados que permiten realizar todas las tareas
(escritura, compilación y ejecución) de forma centralizada y sin tener que ir cambiando de aplicación.
Estos entornos ayudan en las tareas de desarrollo mediante mecanismos como plantillas de clases,
ayudas en línea y depuración asistida, entre otros.

En este manual usaremos el JDK de Sun Microsystems para las tareas de compilación y ejecución. Y
para la edición del código podremos usar nuestro editor preferido, ya sea tan simple como el “Bloc de
notas” de Windows o tan sofisticado como el conocido “vi” de los entornos UNIX. Lo único a tener en
cuenta es que lea y escriba ficheros en formato ASCII.

Para los sistamas DOS, en adelante vamos a suponer que la instalación del JDK la hemos realizado en el
directorio “c:\java”. Y para los sistemas UNIX/Linux supondremos que hemos abierto sesión con el
usuario “usuariojava” y hemos instalado el JDK en el directorio “/home/usuariojava/java”.

3.1.1. El compilador de Java

Es una de las herramientas que se incluyen en el JDK. Se encarga de analizar los ficheros fuente y
generar los correspondientes ficheros compilados (ficheros de bytecodes). En caso de encontrar errores
nos mostrará las líneas que los provocan junto son el mensaje de error que corresponda. Los ficheros
fuente de java tienen la extensión “.java” y los ficheros compilados tienen la extensión “.class”.

- 22 -

Invocaremos el compilador con el comando “javac” seguido del nombre del programa o programas a
compilar. De igual forma, podemos hacer uso de numerosas opciones, las cuales pueden variar de unas
versiones a otras del JDK. En cada caso habremos de consultar la documentación para conocer los
detalles.

3.1.2. El intérprete de Java

Como ya hemos mencionado, Java se diseñó para que el código fuera portable entre plataformas sin
necesidad de volver a compilarlo. Para ello se previó la existencia de un intérprete, más comúnmente
llamado Máquina Virtual de Java (Java Virtual Machine, JVM).

El compilador de Java genera un código que no está relacionado con ninguna plataforma y que,
posteriormente, la JVM interpretará convirtiéndolo al código específico de la plataforma en la que se
ejecuta.

El intérprete se invoca con el comando “java” seguido del nombre del programa a ejecutar. También
permite usar varias opciones y nuevamente nos remitiremos a la documentación para saber los detalles
de cada una de ellas.

3.1.3. Accesibilidad al entorno

Para poder compilar y ejecutar las aplicaciones Java es necesario tener acceso al directorio en el que se
encuentran el compilador y el intérprete. Para poder compilar y ejecutar cómodamente deberíamos añadir
el directorio “\bin” del JDK a la variable de entorno PATH.

Para los usuarios de DOS y Windows, desde el símbolo del sistema tendremos que escribir:
set PATH=%PATH%;c:\java\bin

Para los usuarios de UNIX y Linux: desde la ventana de terminal tendremos que escribir:
export PATH=$PATH:/home/usuariojava/java/bin

- 23 -

En la explicación anterior sólo se cambia la variable de entorno PATH para la sesión en curso (la ventana
actual). Para que el cambio sea permanente debemos consultar la documentación de nuestro sistema.

La variable de entorno PATH no es específica de Java, si no que más bien es un mecanismo de los
sistemas operativos para localizar programas que no se encuentran en el directorio actual. Pero ahora
vamos con otra variable de entorno que sí lo es, estamos hablando de CLASSPATH.

Ya hemos hablado de que Java carga dinámicamente las clases según las necesita, pero ¿dónde busca
esas clases?. Este es el papel de la variable de entorno CLASSPATH, indicar a Java donde buscar las
clases y librerías propias (el API de Java) y las clases de usuario. A partir del JDK versión 1.1.4 sólo es
necesario usar esta variable para indicar las clases de usuario. Esta variable puede incluir tantos
elementos de los siguientes tipos como sea necesario:

• Nombre de directorio que contenga ficheros con extensión “class”.

• Nombre de fichero con extensión “zip” que contenga ficheros con extensión “class”. Recordemos

que un fichero zip es un fichero comprimido.
• Nombre de fichero con extensión “jar” que contenga ficheros con extensión “class”. Los ficheros

jar son ficheros comprimidos con la herramienta jar que incorpora el JDK de Java.

Veamos un ejemplo. Supongamos que disponemos de una librería de clases que vamos a usar
habitualmente y que está comprimida en un fichero llamado “milibreria.zip”. También nos interesa usar un
conjunto de clases sin comprimir que están todas situadas en un mismo directorio llamado “misclases”.

Para los usuarios de DOS y Windows, la librería está en “c:\desarrollo\libreria” y el conjunto de clases está
en “c:\desarrollo\clases”. Desde el símbolo del sistema tendremos que escribir:
set CLASSPATH=.;c:\desarrollo\libreria\ milibreria.zip;c:\desarrollo\misclases

Para los usuarios de UNIX y Linux: la librería está en “/home/usuariojava/desarrollo/libreria” y el conjunto
de clases está en “/home/usuariojava/desarrollo/clases”. Desde la ventana de terminal tendremos que
escribir:

export CLASSPATH=.:/home/usuariojava/desarrollo/libreria/milibreria.zip:
/home/usuariojava/desarrollo/misclases

- 24 -

Como podemos ver, es muy simple. A la variable de entorno CLASSPATH se le asignan tres elementos
de los cuales el primero no se ha explicado. El primer elemento es un “punto”, que en ambos sistemas
representa el directorio en curso. Visto esto, cuando Java necesite cargar una clase de usuario, lo
primero que mirará es si está en el directorio actual, luego buscará en el fichero “milibreria.zip” y, por
último, en el directorio “misclases”. Lo de buscar en primer lugar en el directorio actual es porque resulta
muy común trabajar con clases que residen en una misma ubicación y están relacionadas, por lo que el
cargador de clases debe saber encontrarlas.

Como nota final de este apartado, hemos de indicar que también es posible utilizar la opción “-classpath”
en el momento de llamar al compilador o al intérprete, usando la misma sintaxis y reglas para la variable
de entorno CLASSPATH, pero puede haber pequeñas variaciones entre las distintas versiones del JDK,
por lo que deberá consultarse la documentación correspondiente.

3.2. UN CLÁSICO: HELLO WORLD!

A estas alturas estamos ya estamos en disposición de profundizar en la materia y para ello nada mejor
que empezar por el clásico ejemplo “Hello World!”. A continuación tenemos el código, veámoslo:

1

// Fichero HelloWorld.java

2

class HelloWorld {

3

public static void main(String[] args) {

4

System.out.println(“Hello Word!”);

5

}

6

}

(Los números que encabezan cada línea sólo son para hacer referencia a ellas en las explicaciones y no

formarían parte del código).

A pesar de que puede parecer un código algo oscuro, no obstante, después de analizarlo y explicarlo nos
daremos cuenta de la sencillez del ejemplo.

Línea 1: es un simple comentario de tipo línea en el que hemos colocado el nombre del fichero. El
compilador ignorará todo lo que va desde los caracteres “//” hasta el final de la línea. Como esta línea no

- 25 -

tiene mayores explicaciones, aprovechamos para hacer hincapié acerca del uso comedido de
comentarios en los programas. Tan mala es la falta de comentarios como el abuso de ellos. Pensemos
que los comentarios son de mucha utilidad, tanto para otras personas que tengan que revisar nuestro
código, como para nosotros mismos en futuras revisiones.

Línea 2: declara el nombre de la clase. Usamos la palabra reservada class seguida del nombre que

queremos darle a nuestra clase, en este caso es “HelloWorld”. Ya sabemos que Java es un lenguaje
orientado a objetos, por tanto, nuestro programa ha de ser definido como una clase. Por convención, las
clases Java se definen con la primera letra en mayúsculas.

Línea 3: aparentemente es más compleja, pero veremos que no es así. Estamos ante una declaración de
un método de la clase que estamos definiendo. Este método se llama main, se define como público
(public), estático (static) y no va a devolver nada (void) cuando se ejecute. Se define como público para
que pueda ser conocido fuera de la clase y como estático para disponer de él sin tener que crear un
objeto. Después del nombre, y encerrada entre paréntesis, vemos la definición de los parámetros que
puede recibir el método. En nuestro ejemplo se trata de un parámetro de nombre “args” y de tipo array de
cadenas de texto. Este método será el punto de partida inicial de nuestro programa cuando lo
ejecutemos.

Línea 4: puede resultar extraña para aquellos que no conozcan la sintaxis de la programación orientada a
objetos. Se trata de una llamada al método println del flujo de salida (out) estándar del sistema
(System). Dicho método se encarga de mostrar por pantalla la línea que se le indique.

Las líneas restantes son el cierre de la definición del método main (línea 5) y el cierre de la definición de
la clase HelloWorld (línea 6).

Llegados a este punto es el momento de ponernos manos a la obra. Empezaremos por abrir el editor que
más nos guste, escribir el código anterior, y guardarlo con el nombre “HelloWorld.java”. Es muy
importante tener en cuenta que Java distingue entre mayúsculas y minúsculas. Si nos equivocamos
obtendremos un error que puede resultar algo frustrante para un principiante.

Ahora vamos a compilar nuestra clase. Para ello usaremos la herramienta “javac” indicándole el nombre
de nuestra clase. A continuación vemos como hacerlo:

javac HelloWorld.java

- 26 -

Si lo hemos hecho todo bien no obtendremos ningún mensaje al terminar la compilación y habremos
obtenido un fichero llamado “HelloWorld.class”.

Lo siguiente es la ejecución. Veremos, por tanto, el resultado de nuestro trabajo. Ahora invocaremos al
intérprete, llamado “java”, indicándole qué queremos ejecutar.

java HelloWorld

Y obtendremos como respuesta el texto “Hello World!”. Si no hubiéramos definido la variable de entorno
CLASSPATH, tendríamos que haber usado la sintaxis siguiente:

java –classpath . HelloWorld

Hagamos una reflexión. Cuando invocamos al compilador lo hicimos dándole el nombre y extensión del
fichero a compilar. Por su parte, cuando hemos invocado al intérprete no le hemos indicado el nombre del
fichero y la extensión. ¿Entonces lo que le hemos indicado es el nombre de la clase? ¿Tal vez se trate del
nombre del fichero y se asume la extensión “.class” por defecto? La respuesta es que el intérprete
necesita el nombre de una clase. El nombre del fichero que contiene la clase no es significativo pero por
convención se usa el mismo nombre que el de la clase que contiene. Esto es así porque un fichero puede
contener más de una clase, aunque también por convención no se suele hacer.

Para aclarar todo esto vamos a ver otro ejemplo. Vamos a escribir dos clases: “Clase1” y “Clase2”. La
primera la guardaremos como “Fichero1.java” y la segunda como “Fichero2.java”. Vamos allá.

class Clase1 {

public static void main(String[] args) {
System.out.println(“Soy Clase1”);
}

}

class Clase2 {

public static void main(String[] args) {
System.out.println(“Soy Clase2”);
}

}

- 27 -

Ahora las compilamos usando la siguiente sintaxis para ahorrarnos trabajo:

javac Fichero*.java

Tras esto tendremos los ficheros “Fichero1.class” y “Fichero2.class”. Vamos a hacer varias pruebas y
explicaremos los resultados:

• En primer lugar intentamos ejecutar “Clase1” indicándole el nombre del fichero que la contiene.

Para ello escribimos “java Fichero1”. Veremos que el mensaje de error que obtenemos indica
que no existe la clase “Fichero1”. Así es, no tenemos definida ninguna clase con ese nombre.

• ¿Y si probamos indicándole que nos ejecute “Fichero1.class”? De esa forma debería ejecutarse

“Clase1” ya que está contenida en él. Pues bien, si probamos a escribir “java Fichero1.class”
veremos que obtenemos de nuevo un error en el que se nos indica que no encuentra la clase.
Esta vez el mensaje se refiere a una clase llamada “class” de un paquete llamado “Fichero1” (ya
hablaremos de los paquetes en temas posteriores).

• Ya sólo nos falta indicársela por su nombre, así que ahora escribiremos “java Clase1”. En esta

ocasión observaremos que sí ha funcionado. Si probamos con “java Clase2” vemos que también
la encuentra. Ahora podemos entender la utilidad de indicar el directorio actual en la variable de
entorno CLASSPATH, ya que el intérprete ha encontrado las clases porque estaban accesibles a
través de ella.

Las conclusiones a los puntos anteriores son:

• Para compilar es necesario decirle al compilador el nombre del fichero de clases.

• Para ejecutar hay que indicarle al intérprete cual es la clase que queremos ejecutar y éste la

buscará en los directorios y ficheros especificados en la variable de entorno CLASSPATH.

Para cerrar este apartado, hemos de hacer una aclaración importante. Este último ejemplo ha tratado de
una clase llamada “Clase1” contenida en un fichero llamado “Fichero1.java”. Se ha realizado así por ser
conveniente para lo que se explicaba, pero convencionalmente no se recomienda este uso. Las
recomendaciones indican que el fichero debe poseer el mismo nombre que la clase que contiene.

- 28 -

3.3. CONVENCIONES Y NOMENCLATURA EN LA PROGRAMACIÓN JAVA

Con respecto a los nombres de variables, las reglas del lenguaje Java son muy amplias y permiten mucha
libertad, pero es habitual seguir ciertas normas que faciliten la lectura y el mantenimiento de los
programas. Ya hemos dicho que los nombres en Java son sensibles a mayúsculas y minúsculas. Por
ejemplo, podemos tener en un programa las variables “altura”, “Altura” y “ALTURA” y serían tres variables
distintas.

Por convención, se recomienda seguir las siguientes reglas:

• Normalmente se emplean nombres con minúsculas salvo las excepciones que se enumeran en

los siguientes puntos.

• En los nombres que se componen de varias palabras es aconsejable colocar una detrás de otra

poniendo en mayúscula la primera letra de cada palabra.
• Los nombres de las clases y las interfaces empiezan siempre por mayúscula.

• Los nombres de objetos, métodos y variables empiezan siempre por minúscula.

• Los nombres de las variables finales (las constantes) se definen siempre con mayúsculas.

Veamos a continuación un ejemplo con las reglas anteriormente descritas:

class Circunferencia { // Es una clase
private final double PI = 3.14159; // Es una variable final
private double elRadio; // Es una variable miembro de la clase

public void establecerRadio(double radio) {

// Son un método y una variable local

elRadio = radio;

}
public double calcularLongitud() { // Es un método
return (2 * PI * elRadio);

}

}

- 29 -

RECUERDE

• Para desarrollar y ejecutar aplicaciones Java se necesita un entorno Java.

• El entorno java se Sun Microsystems se llama JDK. Suministra varias herramientas con las
cuales podemos compilar los ficheros fuente y posteriormente ejecutarlos.

• Para la compilación y ejecución de aplicaciones hemos de establecer adecuadamente la variable
de entorno CLASSPATH.

- 31 -

4.1. Palabras clave_____________________________________________________33

4.2. Tipos de datos____________________________________________________33

4.2.1. Tipos primitivos enteros______________________________________34
4.2.2. Tipos primitivos de coma flotante_______________________________34
4.2.3. El tipo primitivo bolean_______________________________________35
4.2.4. Tipos de referencia_________________________________________35

4.3. Operadores_______________________________________________________36

4.3.1. Operadores enteros________________________________________36
4.3.1.1. Operadores numéricos de enteros
4.3.1.2. Operadores de comparación de enteros
4.3.1.3. Operador condicional de enteros
4.3.1.4. Operadores de conversión de tipos enteros
4.3.1.5. Operador entero de concatenación de cadenas
4.3.2. Operadores de coma flotante__________________________________42
4.3.2.1. Operadores numéricos de coma flotante
4.3.2.2. Operadores de comparación de coma flotante
4.3.2.3. Operador condicional de coma flotante
4.3.2.4. Operadores de conversión de tipos de coma flotante
4.3.2.5. Operador de coma flotante de concatenación de cadenas
4.3.3. Operadores booleanos______________________________________44
4.3.3.1. Operadores lógicos de comparación
4.3.3.2. Operador de complemento lógico
4.3.3.3. Operadores lógicos
4.3.3.4. Operadores lógicos condicionales
4.3.3.5. Operador condicional booleano
4.3.3.6. Operador booleano de concatenación de cadenas

Tema 4

PALABRAS CLAVE.
TIPOS DE DATOS.
OPERADORES.
IDENTIFICADORES.
VARIABLES Y
CONSTANTES
LITERALES

- 32 -

4.3.4. Operadores de referencias___________________________________47
4.3.4.1. Operadores de referencias para acceso a campos
4.3.4.2. Operadores de referencias para invocación de métodos
4.3.4.3. Operadores de conversión de tipos de referencia
4.3.4.4. Operador de tipo de referencia
4.3.4.5. Operadores de comparación de referencias
4.3.4.6. Operador condicional
4.3.5. Operadores de asignación____________________________________49
4.3.5.1. Operador de asignación simple
4.3.5.2. Operadores de asignación complejos
4.3.6. Orden de evaluación________________________________________51

4.4. Identificadores____________________________________________________52

4.5. Variables y constantes literales_______________________________________52

4.5.1. Variables_________________________________________________52
4.5.2. Constantes literales_________________________________________54
4.5.2.1. Constantes enteras
4.5.2.2. Constantes de coma flotante
4.5.2.3. Constantes de cadena
4.5.2.4. Constantes booleanas
4.5.2.5. Constante “null”

- 33 -

4.1. PALABRAS CLAVE

Aquéllos que conozcan C++ se irán dando cuenta de que java es muy similar a él en muchos aspectos.
Por ejemplo, ambos lenguajes contienen muy pocas palabras clave. Java se diseñó para que fuera
familiar a los programadores de C++, y por este motivo, las palabras clave de java son muy similares a
las de C++.

A continuación, veremos una tabla con la lista completa de las palabras clave existentes:

abstract

boolean

break

byte

byvalue

case

cast

catch

char

class

const

continue

default

do

double

else

extends

final

finally

float

for

future

generic

goto

if

implements import

inner

instanceof int

interface

long

native

new

operator

outer

package

private

protected

public

rest

return

short

static

super

switch

synchronized this

throw

throws

transient

try

var

void

volatile

while

La tabla anterior contiene algunas palabras que se ignorarían o generarían errores de compilación. Estas
palabras son: byvalue, cast, const, future, generic, goto, inner, operator, outer, rest y var. Por el
momento, no tienen utilidad y están reservadas para proporcionar una mejor detección de errores durante
la compilación.

4.2. TIPOS DE DATOS

Java es un lenguaje sencillo y con pocos tipos de datos, lo cual no implica que no sea potente, de hecho,
es un lenguaje moderno con el que podemos crear prácticamente cualquier tipo de aplicación que se
necesite.

Los tipos de datos se pueden clasificar en dos categorías: los tipos primitivos y los tipos de referencia.

Los tipos primitivos son, al igual que en otros lenguajes, los tipos básicos y no constituyen objetos
propiamente dichos. Entre ellos están los tipos byte, short, int, long, char, float, double y boolean. A su
vez pueden clasificarse en tipos enteros (byte, short, int, long y char), tipos de coma flotante (float y
double) y tipo lógico (bolean).

- 34 -

Los tipos de referencia se usan para hacer referencia a los objetos. Existen tres tipos: las referencias de
objeto, las referencias de interfaz y las matrices.

Para todos los tipos primitivos existe una clase java, dentro del paquete “java.lang”, capaz de representar
a cada uno de ellos como objeto. Estas clases reciben el nombre de “Wrappers” (o envoltorios). Por
ejemplo, java.lang.Byte para el tipo byte, java.lang.Short para el tipo short, etc. Se irán viendo en las
distintas tablas por cada tipo primitivo. Asimismo, todas esas clases tienen su correspondiente método
“toString()”, que devuelve el número convertido a texto.

4.2.1. Tipos primitivos enteros

Como indica su propio nombre, se usan para almacenar números enteros. Las diferencias entre ellos son
los rangos de valores soportados. El tipo byte, por ejemplo, es un entero de 8 bits con signo en
complemento a dos, por lo tanto es capaz de almacenar valores comprendidos entre –128 y 127. Por otra
parte, el tipo short es un entero de 16 bits con signo y en complemento a dos con un rango que va de –
32.768 a 32.767.

Todos los tipos enteros tienen signo y se representan en complemento a dos, excepto el tipo char, que es
un entero sin signo de 16 bits y se usa para representar caracteres Unicode.

Tipo

Tamaño (bits) Rango

Clase asociada

byte

8

-128 a 127

java.lang.Byte

short

16

-32.768 a 32.767

java.lang.Short

Int

32

-2.147.483.648 a 2.147.483.647

java.lang.Integer

long

64

-9.223.372.036.854.775.808

a

9.223.372.036.854.775.807

java.lang.Long

char

16

0 a 65.535

java.lang.Character

4.2.2. Tipos primitivos de coma flotante

Existen sólo dos tipos: float y double, y al igual que ocurría con los enteros, la diferencia está en los
rangos de valores que pueden almacenar. El tipo float es de 32 bits de precisión sencilla, mientras que el
tipo double es de 64 bits y de doble precisión

- 35 -

Ambos pueden representar los siguientes valores:
• El infinito positivo. Es representado por la constante POSITIVE_INFINITY.

• El infinito negativo. Es representado por la constante NEGATIVE_INFINITY.

• El cero positivo.

• El cero negativo.

• Valores que no son numéricos y que se representan por la constante NaN (Not a Number). Estos

valores son generados por operaciones como la división por cero.

• Resto de valores.

Las constantes POSITIVE_INFINITY, NEGATIVE_INFINITY y NaN están declaradas en las clases
java.lang.Float y java.lang.Double. Igualmente, están declaradas las constantes MAX_VALUE y
MIN_VALUE para representar los valores máximo y mínimo que pueden soportar.

Es importante que tengamos en cuenta que aunque se puedan representar el cero positivo y el negativo,
ambos valores se consideran equivalentes en las comparaciones numéricas.

Tipo

Tamaño (bits) Valor máximo

Valor mínimo

Clase asociada

float

32

+-3.4028236e+38

+-1.4e-45

java.lang.Float

double

64

+-1.7984828356536153e+308

+-4.9e-324

java.lang.Double

4.2.3. El tipo primitivo boolean

Sólo existe un tipo y puede tomar los valores “true” (verdadero) y “false” (falso). Al contrario que en otros
lenguajes, por ejemplo en C, no podemos usar los valores enteros en expresiones que requieran valores
booleanos.

4.2.4. Tipos de referencia

Ya hemos visto que los tipos primitivos no son objetos y se utilizan para representar datos. Por el
contrario, los tipos de referencia se emplean para hacer referencia a objetos, interfaces implementadas y
matrices.

- 36 -

Una referencia es esencialmente un puntero a un objeto, pero, a diferencia de los punteros que
conocemos en los lenguajes tradicionales, no podemos obtener el valor al que apunta el puntero, sino
que es el propio Java el que se encarga de obtener el objeto.

Cuando definimos una variable de un tipo de referencia, lo que estamos haciendo es permitir que dicha
variable apunte a instancias de dicha clase, es decir, objetos de dicho tipo. Cuando declaramos una
variable de este tipo y no la inicializamos, tomará el valor constante null.

4.3. OPERADORES

Son símbolos que se utilizan en algunas expresiones para modificar el valor de expresiones más simples,
o bien, para crear expresiones nuevas a partir de otras. Como ejemplo podemos citar el operador de
concatenación de cadenas, que se representa por un signo más (+) y que se usa para concatenar dos
cadenas de texto en una nueva.

Los operadores no son genéricos, sino que se podrán usar dependiendo de las expresiones sobre las que
se quiere operar. Como ejemplo podemos volver a citar el operador de concatenación de cadenas y el
operador de suma de enteros. Aunque ambos se representen con el mismo símbolo (el más de la suma)
no es el mismo operador.

Atendiendo al número de operandos necesitados, los operadores pueden ser de tres tipos:
• Unarios: necesitan un único operador.

• Binarios: necesitan dos operadores.

• Ternarios: necesitan tres operadores.

4.3.1. Operadores enteros

Se pueden dividir en cinco categorías atendiendo a la funcionalidad que suministran.

4.3.1.1. Operadores numéricos de enteros

Como su propio nombre indica, se usan con los números enteros. Atendiendo a la funcionalidad que
ofrecen, se pueden clasificar en distintos tipos.

- 37 -

Los operadores de cambio de signo son dos y se representan por los signos + y – (más y menos). Son
operadores unarios. El operador – se aplica para cambiar el signo del operando, mientras que el operador
+ no tiene ningún efecto. A continuación veremos un ejemplo de ambos operadores:

a = -4; // Asigna el valor –4 a la variable a
b = +7; // Asigna el valor 7 a la variable b

Los operadores aritméticos son operadores binarios. Se utiliza el símbolo + para la suma, el – para la
resta, el * para la multiplicación, el / para la división y el % para la división entera. Veamos los ejemplos
que siguen:

a = 2 + 3; // Se asigna a la variable “a” el valor 5
a = a – 1; // Se asigna a la variable “a” el valor 4
a = a * 4; // Se asigna a la variable “a” el valor 16
a = a / 2; // Se asigna a la variable “a” el valor 8
a = a % 3; // Se asigna a la variable “a” el valor 2

Estas operaciones aritméticas pueden realizarse sobre dos enteros de distinto tipo. En este caso, la
máquina virtual se encarga de convertir el tipo más pequeño al tipo mayor o al tipo “int”, el que sea menor
(en este tipo de operaciones se obtendrá un tipo “int” o un tipo “long”). También hemos de tener en cuenta
que el tipo del resultado de la operación será el mismo que el tipo al que se ha convertido el tipo menor. A
este proceso de conversión se le denomina moldeo o casting. En el siguiente ejemplo veremos
detalladamente el proceso de conversión automática:

byte b = 4;
short s = 2;
int i = b * s;

Las dos primeras sentencias son meras asignaciones a las dos variables que vamos a usar como
operandos de la tercera sentencia. La tercera consiste en la multiplicación de un tipo byte por un tipo
short y la asignación del resultado a una variable de tipo int. En ella tienen lugar las dos conversiones
automáticas que se explican seguidamente:

• Primera conversión: El operando “b” es de tipo byte y hay que multiplicarlo por un operando de

tipo short. Entre ambos tipos, el mayor es el tipo short, pero hemos mencionado que el menor

- 38 -

tipo para una conversión automática es el tipo int, por tanto el operando “b” se convierte a tipo
int.

• Segunda conversión: El operando “s”es de tipo short y hay que multiplicarlo por un operando de

tipo int (obtenido en el paso anterior). Entre ambos tipos el mayor es de tipo int y, por tanto, el
operando “s” se convierte a tipo int.
• Por último, se multiplican ambos operandos de tipo int y el resultado de la operación se

almacena en la variable “i” de tipo int.

Otro tipo de operadores que nos ofrece Java son los operadores de Incremento y Decremento. Son de
uso muy frecuente en estructuras iterativas para las variables de control (los contadores). Los operadores
se representan con los símbolos ++ y -- para aumentar y disminuir, respectivamente, en una unidad al
operando sobre el que actúan.

Pueden utilizarse tanto a modo de prefijo como a modo de sufijo de un operador. Cuando se emplean en
expresiones simples para incrementar o disminuir el valor de una variable, es indistinto el modo en que se
usen. Pero cuando forman parte de expresiones compuestas se diferencian en que el modo prefijo opera
antes que se evalúe el resto de la expresión, mientras que el modo prefijo pospone la operación al resto
de la expresión. Veámoslo claramente en el siguiente ejemplo:

int a = 24;
int b = ++a; // Primero se incrementa y luego se asigna
int c = a++; // Primero se asigna y luego se incrementa

Después de la ejecución del código precedente, la variable “a” vale 26, la variable “b” vale 25 y la variable
“c” también vale 25.

Por otra parte, los operadores de desplazamiento de bits sirven para desplazar los bits de un número
entero. Son tres, el de desplazamiento a la izquierda con signo, el de desplazamiento a la derecha con
signo y el de desplazamiento a la derecha con inserción de ceros. Los símbolos empleados son <<, >> y
>>> respectivamente. Los dos primeros realizan el desplazamiento de bits rellenando los bits más

significativos con el bit de signo del operador. El tercero realiza el desplazamiento rellenando a ceros los
bits más significativos. Estos operadores requieren de dos operandos, el primero es el valor en cuestión
sobre el que se quiere operar, y el segundo indica el número de bits de desplazamiento.

- 39 -

Las siguientes líneas de código nos muestran las diferencias entre estos operadores:

byte a = 1; // Número decimal 1 que en binario sería 00000001
byte b = a << 2; // Desplazamiento de dos bits que da lugar al número 00000100 (4 decimal)
int c = 0xFFFFFFFE; // Valor decimal –2, todos son unos excepto el bit menos significativo
int d = c >> 1; // Desplazamiento con signo. Ahora serían todos unos
int e = c >>> 1; // Desplazamiento sin signo. El bit más significativo se pondría a cero

Para operaciones a nivel de bits, también tenemos el operador de complemento de bits. Se trata de un
operador unario que se encarga de realizar una operación de complemento a unos. En ella, cada bit pasa
de 0 a 1 o de 1 a 0. El símbolo que se emplea es ~. Veamos el siguiente ejemplo para clarificarlo.

byte a = 15; // El valor binario 00001111
byte b = ~a; // Se complementa al valor 11110000 que en decimal es el número -16

También podemos operar con bits usando los operadores de comparación de bits. Son operadores
binarios que permiten comparar dos números atendiendo a sus representaciones binarias y son los
siguientes:

• OR: Se representa por el símbolo |. Da como resultado un 1 si al menos uno de los dos bits

comparados es un 1.

• AND: Se representa por el símbolo &. Da como resultado un 1 si ambos bits comparados son 1.

• XOR: Se representa por el símbolo ^. Da como resultado un 1 si uno, y sólo uno de los dos bits

comparados es un 1.

Como ejemplos de los tres operadores podemos ver los siguientes:

byte a = 1; // La representación binaria sería 00000001
byte b = 3; // La representación binaria sería 00000011
byte c = a | b; // Daría como resultado el valor binario 00000011 (valor decimal 3)
byte d = a & b; // Daría como resultado el valor binario 00000001 (valor decimal 1)
byte e = a ^ b; // Daría como resultado el valor binario 00000010 (valor decimal 2)

- 40 -

Hasta aquí hemos enumerado los distintos tipos de operadores numéricos de enteros. A continuación
vamos a mostrar un cuadro resumen con todos ellos.

Tipo de operador

Operadores asociados

Cambio de signo

-, +

Aritméticos

+, -, *, /, %

Incremento y decremento

++, --

Desplazamiento de bits

<<, >>, >>>

Complemento de bits

~

Comparación de bits

&, |, ^

4.3.1.2. Operadores de comparación de enteros

Se utilizan para comparar dos números enteros y da como resultado un valor booleano. Son los seis que
se muestran en la siguiente tabla:

Operador

Significado

>

Mayor que

<

Menor que

==

Igual a

>=

Mayor o igual que

<=

Menor o igual que

!=

Distinto de

4.3.1.3. Operador condicional de enteros

Es un operador ternario. Construye expresiones que requieren tres operandos y en las cuales el primer y
segundo operando se separan usando el símbolo ? y el segundo y tercer operando se separan usando el
símbolo :. El primer operando debe ser un valor booleano mientras que el segundo y tercero han de ser
valores enteros. Si el valor booleano es true, la expresión toma como valor el del segundo operando,
mientras que en caso contrario toma como valor el del tercer operando.

- 41 -

Es un operador muy usado puesto que permite la toma de decisiones con expresiones muy compactas y
elegantes. Veamos un ejemplo en el cual la última sentencia de asignación es equivalente al bloque “if”
previo. Se trata de saber el mayor de dos números.

if ( a > b ) {

c = a;

} else {

c = b;

}

c = a > b ? a : b;

4.3.1.4. Operadores de conversión de tipos enteros

En el apartado de operadores aritméticos de la categoría de operadores numéricos, hablamos sobre las
conversiones automáticas entre distintos tipos numéricos al efectuar operaciones como la suma. Se
trataba de las conversiones que realiza Java automáticamente. En contraste con éstas, tenemos las
conversiones explícitas de tipos, es decir, aquellas que podemos forzar en el propio código mediante
algún tipo de mecanismo.

Este mecanismo son los operadores de conversión de tipos, que permiten convertir cualquier expresión
numérica a otro tipo distinto. Para cada uno de los tipos numéricos existe un operador de conversión.
Consiste en colocar delante de la expresión a convertir el nombre del tipo al cual se quiere convertir
encerrado entre paréntesis.

En este tipo de conversiones hemos de tener en cuenta que cuando pasamos de un tipo a otro de inferior
rango podemos encontrarnos con resultados inesperados debido a un valor que excede del rango del tipo
al cual se convierte.

Podemos ver los siguientes ejemplos de conversiones:

int a = 24;
byte b = (byte) a;
short c = (short) a;
long d = (long) a;

- 42 -

4.3.1.5. Operador entero de concatenación de cadenas

Cuando una cadena de texto y una expresión que no sea de tipo cadena se combinan usando el operador
de concatenación de cadenas (+), el resultado es una nueva cadena. Dependiendo de la expresión y de
su contenido, podremos obtener los siguientes resultados:

• Si la expresión es un tipo de referencia con valor null, se obtendrá una nueva cadena igual a la
cadena original más la cadena “null”.
• Si la expresión es un tipo de referencia con valor distinto de null, se obtendrá una cadena igual a
la original más el valor devuelto por el método toString() del tipo de referencia.
• Si la expresión es un tipo primitivo, se obtendrá una cadena igual a la original más el valor del
tipo primitivo representado como cadena.

Veamos unos ejemplos sobre las posibles concatenaciones expuestas:

String inicial = “ABC”;
String nulo = null;
String nonulo = “def”;
byte numero = 23;
String caso1 = inicial + nulo; // Se asigna a la variable el valor “ABCnull”
String caso2 = inicial + nonulo; // Se asigna a la variable el valor “ABCdef”
String caso3 = inicial + numero; // Se asigna a la variable el valor “ABC23”

4.3.2. Operadores de coma flotante

Al igual que con los enteros, se pueden clasificar en las mismas cinco categorías según la funcionalidad
que ofrecen. De hecho, la mayoría de los operadores de coma flotante funcionan igual que sus
homólogos enteros, exceptuando los operadores numéricos y los de comparación.

4.3.2.1. Operadores numéricos de coma flotante

Son los mismos que los operadores numéricos de enteros exceptuando los que operaban con los bits, es
decir, los de desplazamiento, complemento y comparación de bits.

- 43 -

Cada uno de ellos funciona de forma similar a los correspondientes de los enteros y no vamos a entrar en
detalles. La principal diferencia está en que el resultado de las operaciones son del tipo de coma flotante.

En la siguiente tabla podemos ver la relación de los operadores existentes para esta categoría.

Tipo de operador

Operadores asociados

Cambio de signo

-, +

Aritméticos

+, -, *, /

Incremento y decremento

++, --

4.3.2.2. Operadores de comparación de coma flotante

Existen los seis mismos tipos que citábamos en el apartado de los enteros. Únicamente existen ciertas
peculiaridades que hemos de observar y que se citan a continuación:

• Ya hemos mencionado que el formato de coma flotante soporta los valores cero positivo y cero

negativo, pero en las comparaciones ambos son equivalentes.

• El valor NaN no es realmente un número, por lo que no se puede decir que dos valores NaN

sean equivalentes. Es decir, tanto el operador == como el operador ¡= devolverían false si los
comparáramos.

En la siguiente tabla mostramos la relación completa de operadores de este tipo:

Operador

Significado

>

Mayor que

<

Menor que

==

Igual a

>=

Mayor o igual que

<=

Menor o igual que

!=

Distinto de

- 44 -

4.3.2.3. Operador condicional de coma flotante

Funciona exactamente igual que el operador condicional de enteros.

4.3.2.4. Operadores de conversión de tipos de coma flotante

Funcionan exactamente igual que los operadores de conversión de tipos enteros.

4.3.2.5. Operador de coma flotante de concatenación de cadenas

Funciona exactamente igual que el operador entero de concatenación de cadenas.

4.3.3. Operadores booleanos

Las condiciones son fundamentales en el control de flujo de ejecución de los programas. Esencialmente,
son expresiones que al ser evaluadas devuelven un valor lógico true o false, también conocido como
booleano.

Existen seis categorías de operadores boléanos y las vamos a tratar en los siguientes apartados.

4.3.3.1. Operadores lógicos de comparación

Hay dos operadores de comparación: igual a (==) y distinto de (!=). Ambos requieren dos operandos de
tipo booleano. El operador == da como resultado true si ambos operandos son iguales. Por el contrario, el
operador != da como resultado true si ambos operandos son distintos.

Veamos unos ejemplos:

true == true // da como resultado true
true == false // da como resultado false
true != true // da como resultado false
true != false // da como resultado true

- 45 -

4.3.3.2. Operador de complemento lógico

Es un operador unario y se representa por el símbolo !. Da como resultado un valor lógico opuesto al
valor lógico del operando sobre el que se aplica. Por ejemplo:

!true // da como resultado false
!false // da como resultado true

4.3.3.3. Operadores lógicos

Para esta categoría existen tres operadores. Los tres son binarios y se emplean para la comparación de
operandos booleanos. Los operadores son los que a continuación se citan:

• OR: Se representa con el símbolo |. Da como resultado un valor true si al menos uno de los

operandos es true.

• AND: Se representa con el símbolo &. Da como resultado un valor true si ambos operandos son

true.

• XOR: Se representa con el símbolo ^. Da como resultado un valor true si uno y sólo uno de los

operadores es true.

Los resultados de estos operadores podemos verlos en los siguientes ejemplos:

true | true // da como resultado true
true | false // da como resultado true
false | false // da como resultado false
true & true // da como resultado true
true & false // da como resultado false
false & false // da como resultado false
true ^ true // da como resultado false
true ^ false // da como resultado true
false ^ false // da como resultado false

- 46 -

4.3.3.4. Operadores lógicos condicionales

Los operadores lógicos condicionales son dos: OR (||) y AND (&&). Funcionan de forma similar a los
operadores lógicos excepto en que no se garantiza la evaluación del segundo operando si el resultado de
la expresión puede determinarse directamente a partir del primero. Esto se conoce como lógica booleana
cortocircuitada. Veamos un ejemplo con la diferencia entre ambos tipos.

int a = 1;
int b = 1;
if ( 3 > 1 | ++a > 0 ) {
// …

}
if ( 3 > 1 || ++b > 0 ) {
// …

}

Tras la ejecución de este código, la variable “a” terminaría con valor 2 mientras que la variable “b”
terminaría con valor 1. La diferencia es que el segundo bloque “if” no necesita evaluar el segundo
operando puesto que el primero es true y, por tanto, el operador devolverá true. Como consecuencia, al
no ejecutarse el segundo operando la variable “b” no se incrementa.

4.3.3.5. Operador condicional booleano

Funciona exactamente igual que el operador condicional de enteros y de coma flotante.

4.3.3.6. Operador booleano de concatenación de cadenas

Funciona exactamente igual que el operador booleano de enteros y de coma flotante. La única diferencia
está en que el resultado de convertir un valor booleano a cadena de texto sería la cadena “true” o la
cadena “false”, según fuera el valor. Vemos un simple ejemplo de concatenación:

“TRUE se convierte en “ + true // da como resultado “TRUE se convierte en true”
“FALSE se convierte en “ + false // da como resultado “FALSE se convierte en false”

- 47 -

4.3.4. Operadores de referencias

Se trata de operadores que operan sobre valores de tipo de referencia, esto es, sobre referencias a
objetos, interfaces y arrays. Existen distintas categorías y vamos a verlas detalladamente a continuación.

4.3.4.1. Operadores de referencias para acceso a campos

El acceso a los campos se realiza mediante el operador punto (.), por ello esta notación también recibe el
nombre de notación de punto. En este tipo de expresiones, el elemento que está a la izquierda del punto
identifica a la clase, objeto o interfaz a la que pertenece el elemento que está a la derecha del punto. Por
ejemplo, para referirnos a la constante “MAX_VALUE” de la clase “Float” lo haríamos con la siguiente
expresión: “Float.MAX_VALUE”.

Existen dos calificadores especiales que se pueden utilizar para acceder a los campos desde el interior
de un objeto. Estos calificadores son las palabras this y super. La primera hace referencia al objeto al
que está asociado el método. La segunda se utiliza para hacer referencia a los campos de la clase padre.

4.3.4.2. Operadores de referencias para invocación de métodos

La invocación de métodos, al igual que para el acceso a campos, se realiza mediante el operador punto.
También pueden usarse los calificadores this y super. Ambos ofrecen la misma funcionalidad que tienen
los correspondientes para el acceso a campos.

4.3.4.3. Operadores de conversión de tipos de referencia

Las operaciones de conversión de tipos se utilizan para convertir una referencia de objeto a un cierto tipo.
Pero existen ciertos requisitos para permitir la conversión. El tipo de un objeto sólo puede convertirse al
de su propia clase, al de una de sus superclases, al de una interfaz que sea implementada por su propia
clase o al de una interfaz que sea implementada por alguna de sus superclases.

- 48 -

Los tipos de referencia se convierten usando como operador el nombre entre paréntesis de la clase a la
cual se quiere convertir y anteponiéndolo a la expresión a convertir. En el siguiente ejemplo se supone la
existencia de dos clases: “FiguraGeometrica” y “Rectangulo”, donde la segunda es descendiente de la
primera.

FiguraGeometrica figura = new Rectangulo ();
Rectangulo rectangulo = (Rectangulo) figura;

4.3.4.4. Operador de tipo de referencia

En Java es sumamente importante la clase a la que pertenece un tipo de referencia. Puesto que se
permite la conversión entre tipos, se hace necesario que podamos comprobar desde el código si una
determinada conversión puede realizarse.

Para determinar si un objeto es una instancia de una clase concreta, disponemos del operador
instanceof que devuelve un valor booleano o genera una excepción. El primer operando debe ser un tipo

de referencia y el segundo debe ser un nombre de clase. Vamos a ver en la siguiente relación los
posibles casos:

• Si el primer operando es null (significaría que no apunta a ningún objeto instanciado), el

resultado es false.
• Si el primer operando es distinto de null y es posible convertirlo a la clase que especifica el

segundo operando, el resultado será true.

• Si el primer operando es distinto de null y no es un descendiente del tipo especificado por el

segundo operando, la instrucción es ilegal y causaría un error de ejecución.

En el siguiente ejemplo se resumen los comportamientos que se acaban de describir:

String s1 = “texto”;
String s2 = null;
boolean b1 = s1 instanceof String; // “b1” toma el valor true
boolean b2 = s2 instanceof String; // “b2” toma el valor false

- 49 -

4.3.4.5. Operadores de comparación de referencias

A diferencia de lo que ocurre con los operadores de comparación de tipos primitivos, que consiste en
comparar los valores de los operandos, el caso de la comparación de tipos de referencia se basa en
comparar que los operandos apunten al mismo objeto. En otras palabras, no es suficiente que los objetos
sean idénticos, si no que han de ser referencias a la misma instancia del objeto.

Existen dos operandos: igual a (==) y distinto de (!=). Ambos devuelven valores booleanos. El primero
devuelve true si tanto el primer operando como el segundo, son referencias al mismo objeto. El segundo
se comporta justamente al revés.

El siguiente ejemplo nos despejará cualquier duda que podamos tener al respecto.

String s1 = “texto”;
String s2 = s1;
String s3 = new String(s1);
boolean b1 = s1 == s2; // “b1” toma el valor true
boolean b2 = s1 == s3; // “b2” toma el valor false

4.3.4.6. Operador condicional

Funciona exactamente igual que el operador condicional de los tipos primitivos. En este caso, el primer
operando debe ser una expresión booleana mientras que el segundo y tercer operandos deben ser de
tipos de referencia.

4.3.5. Operadores de asignación

La asignación es una operación mediante la cual podemos asignar el valor de una expresión a una
variable. La variable a la que se asigna el valor se pone a la izquierda del operador de asignación,
mientras que a la derecha del mismo se pone la expresión. Si la expresión usada requiere una
evaluación, se realiza previa a la asignación.

Existen dos tipos de asignación las cuales vamos a ver seguidamente.

- 50 -

4.3.5.1. Operador de asignación simple

El operador de asignación simple se representa con el símbolo =. Su función es la de evaluar la expresión
del la parte derecha de la expresión de asignación y asignar el resultado a la variable que figura en la
parte izquierda de ella.

Si la expresión y la variable no son compatibles para la asignación, es decir, son de tipos distintos, la
expresión debe convertirse al tipo apropiado antes de la asignación. Si no pudiera convertirse a un tipo
compatible, se produciría un error de compilación.

Este tipo de asignación puede tener lugar, tanto formando parte de la declaración de la variable, como en
cualquier momento posterior a dicha declaración. A continuación veremos unos ejemplos.

int numero = 24; // Declaración y asignación de una variable de tipo primitivo
String texto; // Declaración de una variable de tipo de referencia
texto = “ejemplo”; // Asignación posterior a la declaración

4.3.5.2. Operadores de asignación complejos

La diferencia fundamental de este tipo de operador con respecto al operador simple es que en la
asignación compleja la variable a la que se asigna el valor también participa en la expresión que debe
asignársele. En consecuencia, ello implica que una asignación compleja sólo puede usarse con
posterioridad a la declaración de la variable puesto que necesita utilizarla.

Los operadores de asignación complejos son los siguientes: +=, -=, *=, /=, %=, <<=, >>=, >>>=, |=, &= y
^=. Estos operadores tienen el siguiente comportamiento:

• Se evalúa la expresión que hay a la derecha del operador.

• Se realiza la operación que representa la primera parte del operador (sin considerar el signo

igual) utilizando la variable que hay a la derecha del operador, como primer operando, y la
expresión evaluada en el paso anterior, como segundo operando.
• El resultado obtenido en el paso anterior se asigna a la variable.

- 51 -

Estos operadores no son imprescindibles y se suelen usar para crear sentencias más legibles. Veamos a
continuación unos ejemplos junto con su expresión equivalente usando el operador de asignación simple:

int a = 10;
int b = 3;
a += b; // Equivalente a “a = a + b”
a *= b; // Equivalente a “a = a * b”

Poder usar un tipo de operador de asignación concreto dependerá de los tipos de los operandos. En otras
palabras, los operandos deben ser compatibles con la operación que denota la primera parte del operador
de asignación complejo. Por ejemplo, no podremos usar el operador de asignación “%=” con operandos
de tipo de coma flotante puesto que el operador “%” no es válido para dicho tipo.

4.3.6. Orden de evaluación

A igualdad de condiciones, Java evalúa las expresiones siguiendo un orden estricto de izquierda a
derecha. No obstante, ciertos operadores tienen precedencia sobre otros, por tanto, algunas expresiones
se evaluarán antes que otras.

Cuando una expresión contiene operadores que tienen la misma precedencia, se mantiene el orden de
izquierda a derecha. Ahora bien, cuando alguno de ellos tiene mayor precedencia que el otro, se realiza
primero la operación de mayor precedencia aunque el operador de menor precedencia esté a la
izquierda.

En la siguiente tabla se enumeran los operadores de mayor a menor precedencia. El orden de
precedencia mayor lo proporcionan los paréntesis, mientras que el menor es el de los operadores de
asignación. Los operadores que se encuentran a un mismo nivel tienen igual precedencia y se evaluarán
de izquierda a derecha.

- 52 -

( )
++, --, + (unario), - (unario), ~, !, (conversión de tipo)
*, /, %
+, -
<<, >>, >>>
<, >, <=, >=
==, !=
&
^
|
&&
||
? :
=, +=, -=, *=, /=, %=, <<=, >>=, >>>=, |=, &= y ^=

4.4. IDENTIFICADORES

Los identificadores sirven para nombrar variables, propiedades, métodos, clases, objetos, interfaces y
cualquier otra entidad que sea necesario identificar para poder usar.

En Java, un nombre de identificador debe empezar con una letra, un símbolo de subrayado (_) o un
símbolo dólar ($). El resto de los caracteres empleados pueden ser letras o números. No existe una
longitud máxima y se distinguen las mayúsculas de las minúsculas.

4.5. VARIABLES Y CONSTANTES LITERALES

4.5.1. Variables

Por otro lado, las variables en Java tienen la misma funcionalidad que en el resto de los lenguajes de
programación. Representan direcciones de memoria en las que alojar temporalmente la información que

- 53 -

necesitemos, y por otro, nos ofrecen la facilidad de referirnos a ellas mediante un nombre. Dicho de otra
forma, una variable es un nombre que contiene un valor que puede cambiar a lo largo del programa.

Una declaración de variable se compone de dos partes: su tipo y su nombre. Adicionalmente puede
indicarse un valor para su inicialización. El tipo de la variable determina los valores que puede contener y
las operaciones que se podrán realizar con ella. Según el tipo de información que contienen pueden ser
variables de tipos primitivos o variables de referencia.

Desde el punto de vista del papel que desempeñan, las variables puede ser:

• Variables miembro de una clase: Se definen dentro de la clase y fuera de cualquier método.

• Variables locales: Se definen dentro de un método o, más en general, dentro de cualquier bloque

entre llaves ({ }). Se crean dentro del bloque y se destruyen al finalizar dicho bloque.

Se denomina visibilidad, ámbito o alcance de una variable, a la parte de una aplicación en la que dicha
variable es accesible. En otras palabras, la parte en la cual puede usarse dicha variable. Como norma
general, podemos decir que las variables declaradas dentro de un bloque (entre llaves) son visibles y
existen dentro de ese bloque. Por ejemplo, las variables declaradas al principio de una función existen
mientras se ejecute la función, las declaradas dentro de un bloque “if” sólo serán accesibles y válidas
dentro de dicho bloque y las variables miembro de una clase son válidas mientras existe el objeto.

Las variables miembro de una clase declarada como pública (public), serán accesibles mediante una
referencia a un objeto de dicha clase usando el operador punto. Por su parte, las declaradas como
privadas (private) no son accesibles desde otras clases. Las funciones miembro de una clase tienen
acceso directo a todas las variables miembro de la clase sin necesidad de anteponer el nombre de un
objeto de la clase. Sin embargo, las funciones miembro de una clase “B” derivada de otra “A”, tienen
acceso a todas las variables miembro de “A” declaradas como públicas o protegidas (protected), pero no
a las declaradas como privadas. Una clase hija sólo puede acceder directamente a las variables y
funciones miembro de su clase padre declaradas como públicas o protegidas. Otra característica del
lenguaje Java consiste en que es posible declarar una variable dentro de un bloque con el mismo nombre
que una variable miembro, pero no con el nombre de otra variable local que ya existiera. La variable
declarada dentro del bloque oculta a la variable miembro en ese bloque. Para acceder a la variable
miembro oculta sería necesario que usáramos el operador this.

- 54 -

4.5.2. Constantes literales

Por su parte, las constantes literales son representaciones literales de datos en el código fuente. Estos
valores se emplean para inicializar variables o para usarlas en expresiones en las que se requieren
valores constantes.

Las constantes literales pueden usarse para referirse explícitamente a uno de los tipos siguientes: int,
long, float, double, boolean, char, String y null. En caso de que necesitáramos representar un tipo
primitivo distinto de los indicados, podríamos hacer una conversión explícita al tipo deseado. Por otra
parte, los objetos no pueden ser representados mediante estas constantes, y por tanto, no existen
constantes literales de tipo de referencia.

4.5.2.1. Constantes enteras

Las constantes enteras se representan por un valor que está formado sólo por dígitos numéricos y no
tienen la coma decimal. Si el número no comienza por cero, representa un número decimal (en base 10).
Para representar constantes de tipo “long” se emplea el mismo método pero añadiendo al final la letra “L”.
Está permitido el empleo de la letra “L” en minúsculas, pero no debe usarse ya que puede confundirse
con el número uno.

Además de representaciones en formato decimal, se pueden representar constantes en los formatos octal
y hexadecimal. Las constantes octales se representan anteponiendo un cero al propio número, que
además, sólo podrá estar formado por los dígitos del 0 al 7. Por su parte, las constantes hexadecimales
se representan anteponiendo 0x o 0X y permitiendo que los dígitos del número puedan ser del 0 al 9 y las
letras de la A a la F (en mayúsculas o minúsculas). Las constantes octales y hexadecimales son de tipo
entero a menos que estén seguidas por la letra “L”, en cuyo caso serían de tipo long.

int a = 1002; // Tipo int
long b = 1002L; // Tipo long
int c = 053; // Tipo int en octal
int d = 053L; // Tipo long en octal
int e = 0X002B ; // Tipo int en hexadecimal
int f = 0X002BL; // Tipo long en hexadecimal

- 55 -

El tipo char es un tipo entero, no obstante se trata de un tipo especial pensado para almacenar caracteres
Unicode. Estos últimos son similares a los caracteres ASCII en que están pensados para almacenar
símbolos, números y caracteres. Sin embargo, el rango del tipo char es mucho mayor porque permite
representar caracteres de casi todos los idiomas del mundo.

Las constantes literales de tipo char pueden representarse de dos formas distintas:

• Encerrando un único carácter entre comillas simples.

• Utilizando una secuencia de escape, que es muy útil para representar caracteres que no pueden

escribirse mediante el teclado. La secuencia de escape se representa por una barra inclinada
inversa (\) seguida de un número octal de tres dígitos, o bien por la barra seguida de la letra “u” y
de un número hexadecimal de cuatro dígitos. La secuencia de escape también debe ir encerrada
entre comillas simples. También existe una serie de secuencias de escape especiales que se
utilizan para representar algunos de los caracteres ASCII más comunes. En la siguiente tabla se
relacionan todos.

Secuencia de escape

Carácter que representa

\\

Barra inclinada

\’

Comilla simple

\”

Comilla doble

\b

Espacio

\f

Salto de página

\n

Salto de línea

\r

Retorno de carro

\t

Tabulador

\uFFFF

Escape Unicode

4.5.2.2. Constantes de coma flotante

Se expresan mediante un valor numérico que incluya al menos una posición decimal. A menos que se
indique otra cosa, las constantes de coma flotante serán de tipo double. Para denotar que la constante

- 56 -

sea de tipo float es necesario posponer la letra “f” o “F”. Por claridad, también pueden expresarse las
constantes de tipo double posponiendo la letra “d” o “D” al número.

Este tipo de constantes también pueden expresarse mediante la notación exponencial, que define un
número en dos partes: la mantisa y el exponente. La mantisa es un número en coma flotante con un
dígito significativo y cierto número de decimales. El exponente es un número que representa la potencia
de 10 que multiplica a la mantisa. Entre la mantisa y el exponente se debe poner la letra “e” o “E”.

double a = 123.4; // Tipo double
float b = 123.4F; // Tipo float
double c = 4.502e-12; // Tipo double en notación exponencial.

4.5.2.3. Constantes de cadena

Las constantes de cadena se representan por una secuencia de caracteres encerrados entre comillas
dobles. Dentro de ellas se pueden incluir las secuencias de escape que antes mencionamos. Veamos
algunos ejemplos:

String a = “Texto simple”; // Texto simple
String b = “Esta es la letra \u0041”; // Usando una secuencia de escape para representar la letra “A”
String c = “El proceso ha terminado.\nPulse una tecla”; // Texto en dos líneas

4.5.2.4. Constantes booleanas

Existen dos: true y false. Al contrario que en otros lenguajes de programación, ninguna de estas
constantes puede ser representada mediante un valor entero usando como criterio la igualdad a cero.

4.5.2.5. Constante “null”

Existe una constante nula (null) que podemos usarla para representar el valor null.

- 57 -

RECUERDE

• Existen dos tipos de datos: tipos primitivos y tipos de referencia. Los primeros son los tipos

básicos y no son objetos propiamente dichos, mientras que los segundos se emplean para
representar tipos complejos como objetos, interfaces y matrices.

• Los operadores son símbolos que se utilizan en algunas expresiones para modificar el valor de

expresiones más simples, o bien para crear expresiones nuevas a partir de otras. Java provee
un amplio abanico de operadores clasificados por tipos de datos y funcionalidades. Es
importante que tengamos en cuenta las reglas de precedencia de operadores puesto que van a
determinar los resultados que obtengamos.

• Los identificadores sirven para nombrar variables, propiedades, métodos, clases, objetos,
interfaces y cualquier otra entidad que sea necesario identificar para poder usar.

• Las variables representan direcciones de memoria en las que alojar temporalmente la

información y nos ofrecen la facilidad de referirnos a ellas mediante un nombre. Una declaración
de variable se compone de dos partes: su tipo y su nombre.

• Las constantes literales son representaciones literales de datos en el código fuente. Estos

valores se emplean para inicializar variables o para usarlas en expresiones en las que se
requieren valores constantes.

- 59 -

5.1. Cadenas________________________________________61

5.1.1. La clase String___________________________61
5.1.2. La clase StringBuffer______________________62

5.2. Arrays_________________________________________63

5.2.1 Arrays bidimensionales_____________________65

Tema 5

CADENAS
Y

ARRAYS

- 61 -

5.1. CADENAS

Por cadena se entiende a una secuencia de datos del tipo primitivo carácter (char). También se las
conoce con los nombres de “cadena de caracteres”, “ristra de caracteres” o “string”. En el entorno Java
está implementada mediante las clases String y StringBuffer, ambas pertenecientes al paquete java.lang.

Un uso muy común lo vimos en el tema 4 cuando se hablaron de las constantes literales de cadena. Se
definieron como una secuencia de caracteres encerrados entre comillas dobles. El compilador Java
asigna implícitamente espacio para un objeto de tipo String cuando encuentra una cadena literal.

Los objetos String son invariables, es decir, una vez creados no pueden modificarse. Para solventar esta
situación, Java nos ofrece la clase StringBuffer que permite la creación y manipulación de cadenas de
caracteres. La primera es más eficiente, mientras que la segunda permite más posibilidades.

Es interesante que sepamos que el operador de concatenación (+) de objetos de tipo String utiliza
internamente la clase StringBuffer y el método append(). Además, los métodos de la clase String se
pueden usar directamente sobre cadenas entrecomilladas, por ejemplo: “Java”.length().

5.1.1. La clase String

Los objetos de la clase String se pueden crear a partir de cadenas constantes o literales, definidas entre
dobles comillas. Java crea siempre un objeto String al encontrar una cadena entre comillas. A
continuación se describen dos formas de crear objetos de esta clase:

String a = "Hola"; // Creado automáticamente por Java
String b = new String("Hola"); // Crear con un constructor

El primero de los métodos expuestos es el más eficiente, debido a que al encontrar un texto entre
comillas se crea automáticamente un objeto String. Por otra parte, usando “new” se llama al constructor
dos veces. También se pueden crear objetos de la clase String llamando a otros constructores de la
clase, a partir de objetos StringBuffer, y de arrays de bytes o de chars.

La siguiente tabla muestra algunos de los métodos más importantes de la clase String.

- 62 -

Métodos

Función que realizan

String(...)

Constructores para crear Strings a partir de arrays de bytes o de caracteres

String(String str)
String(StringBuffer sb)

Constructores a partir de un objeto String o StringBuffer

charAt(int)

Devuelve el carácter en la posición especificada
getChars(int, int, char[], int) Copia los caracteres indicados en la posición indicada de un array de
caracteres

indexOf(String, [int])

Devuelve la posición en la que aparece por primera vez un String dentro de
otro y a partir de una posición dada

lastIndexOf(String, [int])

Devuelve la última vez que un String aparece dentro de otro empezando
por el final y a partir de una posición dada

length()

Devuelve el número de caracteres de la cadena

replace(char, char)

Sustituye un carácter por otro en un String

startsWith(String)

Indica si un String comienza con otro String o no

substring(int, int)

Devuelve un String extraído de otro

toLowerCase()

Convierte en minúsculas

toUpperCase()

Convierte en mayúsculas

trim()

Elimina los espacios en blanco al comienzo y final de la cadena

valueOf()

Devuelve la representación como String de sus argumento. Admite Object,
arrays de caracteres y los tipos primitivos

5.1.2. La clase StringBuffer

La clase StringBuffer se utiliza siempre que se desee modificar una cadena de caracteres. Completa los
métodos de la clase String ya que éstos realizan sólo operaciones sobre el texto que no conllevan un
aumento o disminución del número de letras del String.

Recordemos que hay muchos métodos cuyos argumentos deben ser objetos String, por tanto, antes de
pasar esos argumentos habrá que realizar la conversión correspondiente.

La siguiente tabla muestra algunos de los métodos más importantes de la clase StringBuffer.

- 63 -

Métodos

Función que realizan

StringBuffer()
StringBuffer(int)
StringBuffer(String)

Constructores

append(...)

Tiene muchas definiciones diferentes para añadir un String o una variable
(int, long, double, etc.) a su objeto

capacity()

Devuelve el espacio libre del StringBuffer

charAt(int)

Devuelve el carácter en la posición especificada
getChars(int, int, char[], int) Copia los caracteres indicados en la posición indicada de un array de
caracteres

insert(int, )

Inserta un String o un valor (int, long, double, ...) en la posición especificada
de un StringBuffer

length()

Devuelve el número de caracteres de la cadena

reverse()

Cambia el orden de los caracteres

setCharAt(int, char)

Cambia el carácter en la posición indicada

setLength(int)

Cambia el tamaño de un StringBuffer

toString()

Convierte en objeto de tipo String

5.2. ARRAYS

Los arrays, también llamados vectores o matrices, son un tipo especial de referencias, con
independencia de que sean de tipos primitivos o de tipos de referencias. Representan una colección de
elementos del mismo tipo. Una variable de tipo array se declara al igual que cualquier otro tipo de
variable pero incluyendo los corchetes ([ ]).

Los elementos de un array se inicializan al valor por defecto del tipo correspondiente. Cero para valores
numéricos, el carácter nulo para el tipo char, el valor false para el tipo boolean y null para los demás.

Veamos unas explicaciones prácticas basadas en un array de enteros:
int[] arrayEnteros;

- 64 -

La parte “int[]” de la declaración indica que es un array de enteros. En dicha declaración no se asigna
ninguna memoria para contener el array puesto que no se está indicando el número de elementos. Si en
este momento intentáramos acceder a un elemento del array, el compilador daría un error indicando que
el array puede no estar inicializado.

Podemos asignar memoria al array mediante el operador new. A continuación vamos a ver la declaración
anterior junto con la reserva de memoria necesaria para alojar información en el array. En este caso se
trata de un array para almacenar 10 números enteros:
int[] arrayEnteros = new int[10];

Ahora sí que ya sería posible el acceso a los elementos del array. En el ejemplo siguiente vamos a
rellenar el array con los números enteros del 1 al 10:
for (int index = 0; index < arrayEnteros.length; index++) {
arrayEnteros[index] = index + 1;

}

En el ejemplo anterior podemos ver que para hacer referencia a los elementos de un array hemos de usar
los corchetes detrás de su nombre y encerrado entre ellos se coloca el índice del elemento al que se
quiere acceder. También podemos observar que la indexación de los arrays está basada en cero, es
decir, el índice del primer elemento es el cero y el último es uno menor que el número de elementos que
aloja. Otro punto interesante del ejemplo es el uso de la propiedad length para saber el número de
elementos del array.

Otra forma de inicializar un array es asignándole una secuencia de elementos encerrada entre llaves y en
la cual los elementos van separados por una coma. Las siguientes sentencias son equivalentes:
int[] arrayEnteros = new int[10];
int[] arrayEnteros = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Si recordamos el tema 4, estamos ante una constante literal (forma parte del código fuente). En el caso
de arrays de objetos, se pueden inicializar usando el operador new dentro de las llaves como se muestra
en el siguiente ejemplo:
MiClase[] clase = { new MiClase(), new MiClase(), new MiClase() };

Cuando se igualan dos referencias a un array, realmente no se copia el objeto, si no que pasamos a tener
dos referencias que apuntan a un mismo array.

- 65 -

Existe un tipo de array que recibe el nombre de array anónimo, y que consiste en la creación de un array
como argumento actual en la llamada a un método, por ejemplo.

A continuación podemos ver varios ejemplos relacionados con los arrays.

int[] a; // Array de enteros inicializado a null
MiClase[] miClase = new MiClase[5]; // Array de 5 referencias a objetos, todas inicializadas a null
long[] b = new long[10]; // Array de 10 enteros, cada elemento inicializado a cero
double[] v = { 1.3, 3.5, 10.0 }; // Array de 3 elementos inicializados
miObjeto.metodo( new String[] = { “A”, “B”, “C”, “D” } ); //Array anónimo

5.2.1 Arrays bidimensionales

En Java, una matriz es un vector de vectores fila, o más concretamente, un vector de referencias a los
vectores fila. Con este esquema, cada fila podría tener un número de elementos diferente.

Una matriz podemos crearla directamente de la siguiente forma:
int [][] array = new int[3][4];
O bien, podemos crearla dinámicamente con los siguientes pasos:

• Creamos la referencia indicando con corchetes dobles que es una referencia a una matriz

int [][] array;

• Creamos el vector de referencias a las filas.

array = new int[numero_de_filas][];

• Reservamos memoria para los vectores correspondientes a las filas.

for (int index = 0; index < numero_de_filas; index++)
array[index] = new int[numero_de_columnas];

Si tenemos una matriz de nombre “array”, la expresión “array.length” indica el número de filas mientras
que la expresión “array[0].length” indica el número de columnas de la primera fila.

- 66 -

RECUERDE

• Las cadenas son secuencias de datos de tipo char. Cuando se indican en código hay que
encerrarlas entre comillas dobles.

• Java suministra las clases String y StringBuffer para trabajar con cadenas. La primera es más

eficiente pero no permite la manipulación, mientras que la segunda es menos eficiente pero
permite manipular cadenas muy flexiblemente.

• Los arrays son un tipo especial de referencia que permiten representar colecciones de
elementos de un mismo tipo.

- 67 -

6.1. Comentarios de una sola línea______________________69

6.2. Comentarios de varias líneas_______________________69

6.3. Comentarios de documentación_____________________71

6.3.1. El marcador@versión________________________72
6.3.2. El marcador@author_________________________72
6.3.3. E/ marcador@see___________________________72
6.3.4. El marcador@exception_______________________73
6.3.5. El marcador@returns_________________________73
6.3.6. El marcador@param_________________________73
6.3.7. El marcador@deprecated_____________________73

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->