Está en la página 1de 24

Programación Concurrente – Introducción a Java F.

Sánchez

PROGRAMACION EN JAVA
Esta pequeña introducción al lenguaje Java está pensada para estudiantes que están
cursando la asignatura de Programación Concurrente en el tercer curso de las
titulaciones I.I., I.T.I.S. e I.T.I.G. en la Escuela Politécnica de la UEX y a los que se les
presupone conocimientos de C++ o, en general, de Programación Orientada a Objetos.
La mayoría del material aquí expuesto ha sido sacado de varios libros, tutoriales de
Internet y un curso de postgrado sobre el lenguaje Java impartido en la UEX en el curso
99/00. Todos ellos son citados en la Bibliografía de la asignatura disponible en
http://webepcc.unex.es/fernando/concurrente.htm

Introducción

Un poco de historia
Java surgió como resultado de la búsqueda de un lenguaje para programar dispositivos
electrónicos de bajo precio. Este tipo de dispositivos tienen como principales requisitos:
alto grado de portabilidad puesto que los chips cambian frecuentemente y una alta
confiabilidad pues a veces hay que controlar sistemas críticos. Por su parte, un equipo
de trabajo en Sun MicroSystems, liderado por James Gosling, trataba de desarrollar un
nuevo lenguaje de programación sencillo y portable a cualquier entorno de ejecución.
Su primer resultado fue el lenguaje Oak. Era un lenguaje de programación moderno y
potente, eliminando lo innecesario y las fuentes habituales de errores que presentaban
otros lenguajes como C ó C++.
Por problemas en el copyright del lenguaje, Oak tuvo que ser rebautizado como Java.
Concurrentemente en el tiempo (años 90) aparece la World Wide Web en Internet para
acceder con una interfaz gráfica a información en todo el mundo mediante navegadores.
El equipo de Gosling integró Java en un navegador para poder ejecutar los programas
escritos en Java desde cualquier entorno. Así surgió HotJava, un navegador que podía
ejecutar un programa escrito en Java que estuviese en cualquier lugar de la red.

El entorno de desarrollo.
Sun Microsystems proporciona un entorno no visual de desarrollo de forma totalmente
gratuita, lo que es conocido como JDK (Java Development Kit). Existen varias
versiones que han ido incorporando nuevas características a lo largo del tiempo. Aquí
siempre se hará referencia a la versión 1.2.2. que es con la que se trabajará en las clases
prácticas.
Aparte de este JDK, distintas compañías de software han lanzado sus propios entornos
de desarrollo integrados basados en el JDK de Sun, aunque no todas pues como suele
ser habitual Microsoft va por otro lado y tiene su propio JDK no siempre compatible
con el de Sun.
Se pueden destacar:

Nombre Fabricante
JBuilder (Borland)
Visual J ++ (Microsoft)
Java Workshop (Sun)
Visual Café (Symantec)

01/03/2002 1/24
Programación Concurrente – Introducción a Java F. Sánchez

Introducción al lenguaje
Java es un lenguaje orientado a objetos donde todo son clases excepto algunos tipos
primitivos básicos. Sus principales características son:
Orientado a objetos.
Flexible, modular, reutilizable.
Bibliotecas con tipos básicos, I/O, GUI, comunicaciones.
Sencillo, pequeño y simple (hasta cierto punto)
Robusto, potente y flexible.
Gestión automática de memoria.
Independiente de la plataforma hardware.
Multithreaded (multihilo).

Es un lenguaje compilado e interpretado. Del código fuente se pasa a una representación


denominada bytecode (compilación). Más tarde, estos bytecodes serán interpretados por
la máquina virtual java (MVJ) que es la encargada de ejecutar el programa. Estos
bytecodes hacen que Java sea independiente de la plataforma hardware y del sistema
operativo, tanto a nivel fuente como binario. Esto quiere decir que cualquier fuente Java
puede ser compilado en cualquier máquina y S.O. que tenga un compilador Java y que
cualquier fichero de bytecode resultado de compilar un fichero fuente puede ser
ejecutado en cualquier máquina y S.O. que tenga una MVJ. La figura 1 muestra este
proceso. La figura 2 muestra la diferencia entre la compilación normal y el que se sigue
en Java.

Código fuente

javac (compilación)

Bytecodes

java (interpretación)

EJECUCIÓN
Figura 1. Proceso de compilación e interpretación en Java

01/03/2002 2/24
Programación Concurrente – Introducción a Java F. Sánchez

Figura 2. Compilación tradicional frente a compilación Java

Aparte de esta portabilidad, Java también destaca por su soporte multihilo y capacidades
para trabajar con objetos distribuidos e Internet. Precisamente el soporte multihilo es lo
que nos interesa para nuestra asignatura de Programación Concurrente. Sin embargo,
antes de introducirnos con la programación multihilo o multithreading en Java haremos
un breve resumen de las principales características del lenguaje. En primer lugar
veremos un sencillo programa y aprenderemos a compilarlo y ejecutarlo. Seguidamente
se mostrará la sintaxis básica del lenguaje, las clases, la herencia, el polimorfismo, los
interfaces, los paquetes, las excepciones y, por último, la programación multihilo.

Un primer programa
Se puede escribir el programa fuente usando cualquier editor de textos en un archivo
con el mismo nombre que la clase y la extensión .java

/* ------ archivo HolaMundo.java -------*/


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

Todos los programas en Java están compuestos por clases y objetos (instancias de
clases). En nuestro caso, la clase HolaMundo posee un único método y no tiene
atributos. El método main() es el primero que se ejecuta en una aplicación. Toda
aplicación tiene que tener un método main.
public significa que cualquier objeto puede llamarlo
static indica que es un método de clase (lo veremos más adelante)
void significa que es una función que no devuelve ningún valor
El parámetro args hace referencia a los argumentos de entrada, es un vector que va de 0
a numeroDeArgumentos-1.

01/03/2002 3/24
Programación Concurrente – Introducción a Java F. Sánchez

El programa fuente HolaMundo.java se compila con javac para obtener los bytecodes
en el fichero HolaMundo.class
> javac HolaMundo.java /* ¡Ojo! Hay que poner la extensión */

Ejecutamos los bytecodes con el intérprete java


> java HolaMundo /* ¡Ojo! Sin la extensión .class */

El resultado sería la salida en pantalla del mensaje: Hola Mundo.

LOS APPLETS
Un applet es un programa dinámico e interactivo que puede ejecutarse dentro de una
página WEB. Los applets permiten mostrar imágenes, tener animaciones, entrada y
salida de datos interactiva, juegos, efectos gráficos y sonoros, etc.
Para crear un applet, hay que escribir la aplicación correspondiente en Java, compilarla,
y referenciarla desde una página HTML. Escribiremos la aplicación anterior como un
applet. Primero escribimos el programa fuente en un archivo con el mismo nombre que
la clase y la extensión .java. Hay que incluir dos sentencias import para poder utilizar
las clase Applet y Graphics respectivamente. De momento, pensemos que la sentencia
import es como un include de C++ o un uses de Pascal. Todo applet tiene que heredar
de la clase Applet.

/* ------ archivo AppletHolaMundo.java -------*/


import java.applet.Applet;
import java.awt.Graphics;

public class AppletHolaMundo extends Applet{


public void paint(Graphics g){
g.drawString("Hola Mundo", 5, 25);
}
}

El programa fuente AppletHolaMundo.java se compila con el compilador javac de JDK


para obtener los bytecodes en el fichero AppletHolaMundo.class

> javac AppletHolaMundo.java /* con la extensión */

Hay que crear una página en HTML con una referencia a la clase del applet.

<html>
<head>
<tittle> Esta página contiene un applet de ejemplo </tittle>
</head>
<body>
Esta es la salida del applet:
<br>
<applet code="AppletHolaMundo.class" width=200 height=50>

01/03/2002 4/24
Programación Concurrente – Introducción a Java F. Sánchez

</applet>
</body>
</html>

Figura 3. Aspecto de un browser visualizando el applet

El applet también se puede ver con appletviewer


appletviewer AppletHolaMundo.html

Figura 4. La herramienta appletViewer

No nos ocuparemos más de los applets en estos apuntes, simplemente se pretendía


hacer una pequeña introducción, pero cualquier ejemplo que aquí veamos podría
haberse codificado como un applet siguiendo los pasos aquí expuestos.

Comparación con C/C++


Algunas características que presenta o no presenta Java con respecto a C++:
- Sin contexto. No hay archivos de cabecera, ni #define ni typedefs)
- Sin estructuras o registros (no son necesarios; hay clases)
- No hay funciones ni procedimientos (hay métodos)
- No hay herencia múltiple (existe la noción de interface)
- No hay goto
- No hay sobrecarga de operadores aritméticos (hay clases)
- No hay conversión automática de tipos
- No hay punteros
- Gestión automática de la memoria (Garbage Collector)
- Java posee librerías estándar para tareas específicas como:

01/03/2002 5/24
Programación Concurrente – Introducción a Java F. Sánchez

- Multithreading
- Redes
- Conexión con BD
- Distribución

Sintaxis básica del lenguaje

Comentarios
En Java hay tres tipos de comentarios:

// comentarios para una sola línea


/* comentarios de una o
más líneas, al estilo C++
*/
/** comentario de documentación, de una o más líneas.
Útil para la herramienta JavaDoc
*/

Los dos primeros tipos de comentarios son los que todo programador conoce y se
utilizan del mismo modo. Los comentarios de documentación, colocados
inmediatamente antes de una declaración (de variable o función), indican que ese
comentario ha de ser colocado en la documentación que se genera automáticamente
cuando se utiliza la herramienta de Java javadoc.

IDENTIFICADORES
En Java, un identificador comienza con una letra, un subrayado (_) o un símbolo de
dólar ($). Los siguientes caracteres pueden ser letras o dígitos. Se distinguen las
mayúsculas de las minúsculas y no hay longitud máxima.

PALABRAS CLAVE
Las siguientes son las palabras clave que están definidas en Java y que no se pueden
utilizar como indentificadores:

abstract continue for new switch


boolean default goto null synchronized
break do if package this
byte double implements private threadsafe
byvalue else import protected throw
case extends instanceof public transient
catch false int return true
char final interface short try
class finally long static void
const float native super while

01/03/2002 6/24
Programación Concurrente – Introducción a Java F. Sánchez

PALABRAS RESERVADAS
Además, el lenguaje se reserva unas cuantas palabras más, pero que hasta ahora no
tienen un cometido específico. Son:
cast future generic inner operator outer rest var

TIPOS DE DATOS PRIMITIVOS


Existen ocho tipos básicos primitivos. No son objetos, pertenecen al sistema. Existen
clases que actúan como contenedores de estos tipos básicos de datos para sustituirlos
cuando hay que utilizar objetos para representar estos tipos.

Enteros
byte 8 bits complemento a dos
short 16 bits complemento a dos
int 32 bits complemento a dos
long 64 bits complemento a dos
Reales en coma flotante
float 32 bits IEEE 754
double 64 bits IEEE 754
Booleanos (boolean)
true
false
Caracteres
Son 16 bits sin signo. Se representan dentro de un par de comillas simples (' ').
Por ejemplo: 'a' '\t' '\u????' donde [????] es un número unicode.
Unicode es el juego de caracteres usado por Java

Java dispone de clases para cada uno de los tipos básicos. Cada clase tiene un método
para acceder al valor que encapsula.

Tipo Nombre de la clase Método de acceso al valor


byte Byte byteValue ( )
short Short shortValue ( )
int Integer intValue ( )
long Long longValue ( )
float Float floatValue ( )
double Double doubleValue ( )
char Character charValue ( )
boolean Boolean booleanValue ( )

byte b;
Byte ob = new Byte (5); // creamos un objeto Byte con el valor 5
b = ob.byteValue(); /* asignamos a b (tipo primitivo) el valor almancenado
en el objeto ob */

01/03/2002 7/24
Programación Concurrente – Introducción a Java F. Sánchez

LITERALES
Los valores constantes se crean utilizando una representación literal. Cada literal tiene
un tipo simple asociado con su valor.
Por omisión, un valor entero es int: 17 345
Un entero long lleva una L detrás: 134L
Por omisión, un valor real es double: 23.79 1.5e3
Un valor real float lleva una f detrás: 12.67f
Los valores booleanos son true y false
Los caracteres se almacenan en formato Unicode
Un carácter se representa entre comillas simples
‘a’ ‘A’ ‘3’ ‘\t’ ‘\u????’ (???? es un número)
Existen unos caracteres con significado especial:

\n Nueva línea \f Formfeed


\t Tabulación \\ BackSlash
\b Backspace \' Comilla simple
\r Retorno de carro \" Comilla doble
\ddd Octal \xdd Hexadecimal
\udddd Carácter Unicode

CADENAS DE CARACTERES
Series de caracteres entre comillas dobles. Son instancias de la clase String

Ejemplos
" Esto es una cadena de caracteres"
" Esto también, con un \t tabulador"
" Y esto también, con \"comillas\" en la cadena"

ARRAYS
Se pueden declarar en Java arrays de cualquier tipo:

char s[];
int iArray[];

Incluso se pueden construir arrays de arrays:


int tabla[][] = new int[4][5];

Los límites de los arrays se comprueban en tiempo de ejecución para evitar


desbordamientos y la corrupción de memoria. En Java un array es realmente un objeto
que tiene redefinido el operador []. Tiene una función miembro: length. Se puede
utilizar este método para conocer la longitud de cualquier array.
int a[][] = new int[10][3];
a.length; /* 10 */
a[0].length; /* 3 */

01/03/2002 8/24
Programación Concurrente – Introducción a Java F. Sánchez

Para crear un array en Java hay dos métodos básicos. Crear un array vacío, en cuyo caso
hay que utilizar el operador new:
int lista[] = new int[50];

o se puede crear ya el array con sus valores iniciales:


String nombres[] = {
"Juan","Pepe","Pedro","Maria"
};

Esto último es equivalente a:


String nombres[];
nombres = new String[4];
nombres[0] = new String( "Juan" );
nombres[1] = new String( "Pepe" );
nombres[2] = new String( "Pedro" );
nombres[3] = new String( "Maria" );

No se pueden crear arrays estáticos en tiempo de compilación:


int lista[50]; // generará un error en tiempo de compilación

Tampoco se puede rellenar un array sin declarar el tamaño con el operador new:
int lista[];
for( int i=0; i < 9; i++ )
lista[i] = i;

Es decir, todos los arrays en Java son estáticos. Para convertir un array en el equivalente
a un array dinámico en C/C++, se usa la clase Vector proporcionada por Java, que
permite operaciones de inserción, borrado, etc. en el array.

OPERADORES
Los operadores de Java son muy parecidos en estilo y funcionamiento a los de C. En la
siguiente tabla aparecen los operadores que se utilizan en Java, por orden de
precedencia:

. [] ()
++ --
! ~ instanceof
* / %
+ -
<< >> >>>
< > <= >= == !=
& ^ |
&& ||
? :
= op= (*= /= %= += -= etc.) ,

01/03/2002 9/24
Programación Concurrente – Introducción a Java F. Sánchez

Los operadores numéricos se comportan como esperamos:


int + int = int

Los operadores relacionales devuelven un valor booleano.


Para las cadenas, se pueden utilizar los operadores relacionales para comparaciones
además de + y += para la concatenación:
String nombre = "nombre" + "Apellido";

El operador = siempre hace copias de objetos en el caso de las cadenas, marcando los
antiguos para borrarlos, y ya se encargará el garbage collector de devolver al sistema la
memoria ocupada por el objeto eliminado. El garbage collector simplemente es una
tarea de fondo que se encarga de eliminar aquellos objetos que no están siendo
utilizados por el programa.

SEPARADORES
Los separadores admitidos en Java son:
() - paréntesis. Para contener listas de parámetros en la definición y llamada a
métodos. También se utiliza para definir precedencia en expresiones, contener
expresiones para control de flujo y hacer las conversiones de tipo.
{} - llaves. Para contener los valores de matrices inicializadas automáticamente.
También se utiliza para definir un bloque de código, para clases, métodos y ámbitos
locales.
[] - corchetes. Para declarar tipos matriz. También se utiliza cuando se referencian
valores de matriz.
; - punto y coma. Separa sentencias.
, - coma. Separa identificadores consecutivos en una declaración de variables.
También se utiliza para encadenar sentencias dentro de una sentencia for.
. - punto. Para separar nombres de paquete de subpaquetes y clases. También se
utiliza para separar una variable o método de una variable de referencia.

CONTROL DE FLUJO
Muchas de las sentencias de control del flujo del programa se han tomado del C:

1.1.1 SENTENCIAS DE SALTO


if/else
if( Boolean ) {
sentencias;
}
else {
sentencias;
}

switch
switch( expr1 ) {
case expr2:
sentencias;
break;
case expr3:

01/03/2002 10/24
Programación Concurrente – Introducción a Java F. Sánchez

sentencias;
break;
default:
sentencias;
break;
}

1.1.2 SENTENCIAS DE BUCLE


Bucles for
for( expr1 inicio; expr2 test; expr3 incremento ) {
sentencias;
}

También se soporta el operador coma (,) en los bucles for


for( a=0,b=0; a < 7; a++,b+=2 )

Bucles while
while( Boolean ) {
sentencias;
}

Bucles do/while
do {
sentencias;
} while( Boolean );

1.1.3 CONTROL GENERAL DEL FLUJO

break [etiqueta]
continue [etiqueta]
return expr;
etiqueta: sentencia;

En caso de que nos encontremos con bucles anidados, se permite el uso de etiquetas
para poder salirse de ellos, por ejemplo:
uno: for( )
{
dos: for( )
{
continue; // seguiría en el bucle interno
continue uno; // seguiría en el bucle principal
break uno; // se saldría del bucle principal
}
}

En el código de una función siempre hay que ser consecuentes con la declaración que se
haya hecho de ella. Por ejemplo, si se declara una función para que devuelva un entero,
es imprescindible que se coloque un return final para salir de esa función,
independientemente de que haya otros en medio del código que también provoquen la

01/03/2002 11/24
Programación Concurrente – Introducción a Java F. Sánchez

salida de la función. En caso de no hacerlo se generará un warning, y el código Java no


se puede compilar con warnings.
int func() {
if( a == 0 )
return 1;
return 0; // es imprescindible porque se retorna un entero
}

CLASES
Todo en Java son clases. No hay funciones ni variables globales. Todos los datos
básicos, como los enteros, se deben declarar en las clases antes de hacer uso de ellos. En
C la unidad fundamental son los ficheros con código fuente, en Java son las clases. De
hecho son pocas las sentencias que se pueden colocar fuera del bloque de una clase. La
palabra clave import (equivalente al #include) puede colocarse al principio de un
fichero, fuera del bloque de la clase. Sin embargo, el compilador reemplazará esa
sentencia con el contenido del fichero que se indique, que consistirá, como es de
suponer, en más clases.
Una clase debe implementarse en un archivo con el mismo nombre. La declaración e
implementación se hace en el mismo archivo.
El nombre de las clases es case sensitive. Empiezan por mayúscula (convención).
Una aplicación se compone de varias clases más una clase con un método especial
llamado main.

ESTRUCTURA BÁSICA DE UNA CLASE


La estructura básica de una clase es:
modificadorClase class nombre_de_clase {

modificadorVar type variable_de_instancia1;


modificadorVar type variable_de_instancia2;
modificadorVar type variable_de_instanciaN;

modificadorMetodo type nombre_de_método1 (lista_de_parámetros) {


//cuerpo_del_método;
}
modificadorMetodo type nombre_de_métodoN (lista_de_parámetros) {
//cuerpo_del_método;
}
}

Por defecto toda clase hereda de Object, que es la raíz de la jerarquía de clases en Java.
Veamos un ejemplo de una clase Book que contiene 3 atributos privados de clase, un
constructor y 3 métodos públicos para acceder a los atributos. La clase es pública
también. Hay que hacer notar que String es una clase de Java mientras que int es un tipo
primitivo, no es una clase.

public class Book { // clase pública. Accesible por cualquier clase


private String title, author; // privados, sólo conocidos en esta clase
private int isbn;

01/03/2002 12/24
Programación Concurrente – Introducción a Java F. Sánchez

public Book (String t, String a, int n) {


title =t; author = a; isbn = n;
}
public String get_author() {
return author;
}
public int get_isbn() {
return isbn;
}
public String get_title() {
return title;
}
}

MODIFICADORES DE MÉTODOS Y VARIABLES


public
Variables y métodos pueden ser accedidos desde fuera.
private
Variables y métodos sólo pueden ser accedidos desde esta clase.
static
- para variables y métodos comunes a los objetos pertenecientes a una clase. Todos los
objetos pertenecientes a la clase donde se declaren comparten las mismas intancias de
variables y métodos declarados como static.
- los métodos static sólo pueden acceder a variables y métodos static. Esto es algo
importante a tener en cuenta al trabajar con el método main que es static.
- bloques static de inicialización: sólo se ejecutan cuando se carga la clase.
abstract
- métodos que han de ser sobreescritos en las subclases.
final
- no pueden ser sobreescritos en las subclases.
- para los atributos es como una definición de constante.

1.1.4 Ejemplo de variables y métodos de instancia

public class MiClase {


private int i=0; // Cada objeto tiene su propia variable i
public void Suma (int j) {
i = i + j;
}
}

1.1.5 Ejemplo de variables y métodos de clase

public class OtraClase {

01/03/2002 13/24
Programación Concurrente – Introducción a Java F. Sánchez

static int cont=0; // compartido por todos los objetos de la clase


OtraClase () {
cont++;
}
}

CREACIÓN DE OBJETOS
Consideremos la siguiente clase:

class Point {
int x, y;
Point (int cx, int cy) {
x = cx; y = cy; }
Point () {
x = -1; y = -1; }
public void Origen() {
x = 0; y = 0; }
}

Se puede observar que el constructor tiene el mismo nombre que la clase, sin devolver
tipo. Puede haber tantos constructores como se quiera, pero con distinta signatura.
- Creación de una instancia:
Point p = new Point(3,4);
Point p = new Point();
- Llamada a métodos:
p.Origen();

Considerando el caso anterior de las clases MiClase y OtraClase:


MiClase a =
new MiClase();
MiClase b =
new MiClase();
OtraClase c
= new OtraClase();
OtraClase d
= new OtraClase(); // cont vale 2. Es la misma variable para c y
// d. Cada vez que se crea una instancia se
// incrementa cont.
a.Suma (2); // la i de a vale 2
b.Suma (3); // la i de b vale 3. Son variables distintas

REFERENCIAS A OBJETO
Cuando tenemos algo como Point p; hay que tener en cuenta que p es una referencia a
una instancia de Point, no es una instancia, tiene un valor null. p es compatible con
instancias de subclases (clave para el polimorfismo).
Una referencia es parecido al concepto de puntero. La diferencia es que no se pueden
manipular como si fueran enteros tal y como se hace en C o C++.
Cada referencia apunta a una estructura de datos con información del tipo y dirección
real del objeto.
Puede haber múltiples referencias a un mismo objeto.
Cuando se le pasa un objeto a un método como argumento:

01/03/2002 14/24
Programación Concurrente – Introducción a Java F. Sánchez

- Se pasa la referencia al objeto


- NO se duplica el objeto

PASO DE ARGUMENTOS EN JAVA


Java pasa todos los argumentos por valor. Realmente se pasan referencias a los objetos.
La referencia no cambiará aunque se modifique dentro del método. El objeto sí puede
modificarse dentro del método.
Veamos un ejemplo:

import java.awt.Point;
class Cambia {
public static void main(String args[ ]) {
Point p1 = new Point(0,0);
cambia(p1);
System.out.println(p1);
}
static void cambia(Point p) {
p.x = 38;
p.y = 97;
}
}

import java.awt.Point;

class NoCambia {
public static void main(String args[ ]) {
Point p1 = new Point(0,0);
noCambia(p1);
System.out.println(p1);
}
static void noCambia(Point p) {
p = new Point(38, 97);
}
}

El resultado sería:
C:\CJava>java Cambia
java.awt.Point[x=38,y=97]

C:\CJava>java NoCambia
java.awt.Point[x=0,y=0]

Del ejemplo se deduce también que se puede imprimir un objeto directamente. En ese
caso se imprime el valor de sus atributos.

MODIFICADORES DE CLASES
Los tipos de clases que podemos definir son:

01/03/2002 15/24
Programación Concurrente – Introducción a Java F. Sánchez

abstract
Una clase abstract tiene al menos un método abstracto. Una clase abstracta no se
instancia, sino que se utiliza como clase base para la herencia.

final
Una clase final se declara como la clase que termina una cadena de herencia. No se
puede heredar de una clase final.

public
Las clases public son accesibles desde otras clases, bien sea directamente o por
herencia. Son accesibles dentro del mismo paquete en el que se han declarado. Para
acceder desde otros paquetes, primero tienen que ser importadas. Los conceptos de
paquete e importación se ven más adelante.

HERENCIA
Para heredar se utiliza la palabra reservada extends. Supongamos que queremos crear un
punto en 3 dimensiones.

class Point3D extends Point {


int z;
Point3D (int x, int y, int z) {
super (x,y);
this.z = z;
}
Point3D() {
this (-1,-1,-1);
}
}

La palabra reservada super referencia a la superclase. En este caso estamos llamando al


constructor de la superclase. this referencia al objeto actual.
En Java no existe la herencia múltiple.

CONTROL DE ACCESO
Cuando se crea una nueva clase en Java, se puede especificar el nivel de acceso que se
quiere para las variables de instancia y los métodos definidos en la clase:

public
public void CualquieraPuedeAcceder(){}
Cualquier clase desde cualquier lugar puede acceder a las variables y métodos de
instancia públicos.
protected
protected void SoloSubClasesYMismoPaquete(){}
Sólo las subclases de la clase y las clases del mismo paquete pueden acceder a las
variables y métodos de instancia protegidos.
private

01/03/2002 16/24
Programación Concurrente – Introducción a Java F. Sánchez

private String SoloEstaClase;


Las variables y métodos de instancia privados sólo pueden ser accedidos desde dentro
de la clase. No son accesibles desde las subclases.
friendly
(sin declaración específica)
void AccedenDelMismoPaquete(){}

Por defecto, si no se especifica el control de acceso, las variables y métodos de instancia


se declaran friendly (amigas), lo que significa que son accesibles por todos los objetos
dentro del mismo paquete, pero no por los externos al paquete.

A continuación se presenta un cuadro resumen del control de acceso:

private sin modif. protected public


misma clase sí sí sí sí
sublcase de mismo no sí sí sí
paquete
no subclase de mismo no sí sí sí
paquete
subclase de diferente no no sí sí
paquete
no subclase de diferente no no no sí
paquete

CARACTERÍSTICAS DE LA HERENCIA
A cualquier referencia de X se le puede asignar un objeto derivado de X
Principales características: (si B extiende a A)
B tiene acceso a los atributos y métodos públicos y protegidos de A
B implementa todos los interfaces implementados por A
B exporta todos los atributos y métodos públicos de A.
B no puede restringir el acceso a ningún miembro de A.
B puede hacer público cualquier método protegido de A.
Cualquier método en B con la misma signatura que en A, lo redefine.
B puede añadir nuevos métodos y atributos.

ENLACE DINÁMICO
Cuando tenemos algo como: A.metodo();, siendo A superclase de B
En t. de compilación: se comprueba si metodo existe en A. Si no « error de
compilación
En t. de ejecución: A puede ser realmente una referencia a un objeto subclase
de la clase declarada para A. Se ejecuta el método de la subclase.

Veamos un ejemplo:

class Base {
public void op1(){System.out.println(“Base”);}

01/03/2002 17/24
Programación Concurrente – Introducción a Java F. Sánchez

}
class Derived extends Base {
public void op1(){System.out.println(“Deriv”);}
}
class Main {
public static void main (String args[]) {
Derived d = new Derived();
Base b = d;
b.op1(); // se imprime Deriv
d.op1(); // se imprime Deriv
}
}

No ocurre lo mismo para las variables de instancia.

INTERFACES
Los métodos abstractos son útiles cuando se quiere que cada implementación de la clase
parezca y funcione igual, pero necesita que se cree una nueva clase para utilizar los
métodos abstractos.
Los interfaces proporcionan un mecanismo para abstraer los métodos a un nivel
superior. Un interface contiene una colección de métodos que se implementan en otro
lugar. Los métodos de una clase son public, static y final.
La principal diferencia entre interface y abstract es que un interface proporciona un
mecanismo de encapsulación de los protocolos de los métodos sin forzar al usuario a
utilizar la herencia.
Por ejemplo:

public interface VideoClip {


void play();// comienza la reproduccion del video
void bucle();// reproduce el clip en un bucle
void stop();// detiene la reproduccion
}

Las clases que quieran utilizar el interface VideoClip utilizarán la palabra implements y
proporcionarán el código necesario para implementar los métodos que se han definido
para el interface:

class MiClase implements VideoClip {


void play() {
<código>
}
void bucle() {
<código>
}
void stop() {
<código>
}
}

01/03/2002 18/24
Programación Concurrente – Introducción a Java F. Sánchez

Al utilizar implements para el interface es como si se hiciese una acción de copiar-y-


pegar del código del interface, con lo cual no se hereda nada, solamente se pueden usar
los métodos.
La ventaja principal del uso de interfaces es que una clase interface puede ser
implementada por cualquier número de clases, permitiendo a cada clase compartir el
interfaz de programación sin tener que ser consciente de la implementación que hagan
las otras clases que implementen el interface.

class MiOtraClase implements VideoClip {


void play() {
<código nuevo>
}
void bucle() {
<código nuevo>
}
void stop() {
<código nuevo>
}
}

También se utilizan los interfaces para compartir constantes entre varias clases:

interface SharedConstants {
int NO = 0;
int YES = 1;
int MAYBE = 2;
}

class Question implements SharedConstants {


...
}
class AskMe implements SharedConstants {
...
}

Ambas clases compartirían las mismas constantes.

PAQUETES
La palabra clave package permite agrupar clases e interfaces. Los nombres de los
paquetes son palabras separadas por puntos y se almacenan en directorios que coinciden
con esos nombres.
Por ejemplo, los ficheros siguientes, que contienen código fuente Java y están en el
paquete denominado applet:
Applet.java, AppletContext.java, AppletStub.java, AudioClip.java
contienen en su código la línea:
package java.applet;

01/03/2002 19/24
Programación Concurrente – Introducción a Java F. Sánchez

Y las clases que se obtienen de la compilación de los ficheros anteriores, se encuentran


con el nombre
nombre_de_clase.class, en el directorio: java/applet

IMPORT
Los paquetes de clases se cargan con la palabra clave import, especificando el nombre
del paquete como ruta y nombre de clase (es lo mismo que #include de C/C++). Se
pueden cargar varias clases utilizando un asterisco.
import java.Date;
import java.awt.*;

Si un fichero fuente Java no contiene ningún package, se coloca en el paquete por


defecto sin nombre. Es decir, en el mismo directorio que el fichero fuente, y la clase
puede ser cargada con la sentencia import:
import MiClase;

PRINCIPALES PAQUETES DE JAVA


El lenguaje Java proporciona una serie de paquetes que incluyen ventanas, utilidades, un
sistema de entrada/salida general, herramientas y comunicaciones. Entre otros, en la
versión actual del JDK, los paquetes Java que se incluyen son:

java.applet
Este paquete contiene clases diseñadas para usar con applets. Hay una clase Applet y
tres interfaces: AppletContext, AppletStub y AudioClip.

java.awt
El paquete Abstract Windowing Toolkit (awt) contiene clases para generar widgets y
componentes GUI (Interfaz Gráfico de Usuario). Incluye las clases Button, Checkbox,
Choice, Component, Graphics, Menu, Panel, TextArea y TextField.

java.io
El paquete de entrada/salida contiene las clases de acceso a ficheros: FileInputStream y
FileOutputStream.

java.lang
Este paquete incluye las clases del lenguaje Java propiamente dicho: Object, Thread,
Exception, System, Integer, Float, Math, String, etc.

java.net
Este paquete da soporte a las conexiones del protocolo TCP/IP y, además, incluye las
clases Socket, URL y URLConnection.

java.util
Este paquete es una miscelánea de clases útiles para muchas cosas en programación. Se
incluyen, entre otras, Date (fecha), Dictionary (diccionario), Random (números
aleatorios) y Stack (pila FIFO).

01/03/2002 20/24
Programación Concurrente – Introducción a Java F. Sánchez

GESTIÓN DE EXCEPCIONES
Una excepción es una condición anormal que surge en una secuencia de código durante
la ejecución de esa secuencia. En otros lenguajes de programación se utilizaban códigos
de retorno para controlar el tipo de error que ocurría en el código llamado. Era muy
común por ejemplo ver en C una variable llamada errno para controlar el tipo de error
producido.
En Java la gestión de excepciones se realiza mediante objetos. Una excepción en Java
será un objeto que describe una condición excepcional que se produce en un fragmento
de código. Las excepciones pueden aparecer de manera asíncrona en un método o
pueden ser creadas manualmente y enviadas para informar de alguna condición de error
al método que realizó la llamada.
Cinco son las palabras clave para gestionar las excepciones en Java. Básicamente, el
protocolo del manejo de las excepciones es el siguiente: se intenta (try) ejecutar un
bloque de código, y si se produce un error, el sistema lanza (throws) una excepción que
se puede capturar (catch) en base al tipo de la excepción o ser tratada finalmente
(finally) por un gestor por omisión.

La forma básica del bloque es la siguiente:

try {
// bloque de código
} catch (TipoExcepcion_1 e) {
// gestor de excepciones para TipoExcepcion1
} catch (TipoExcepcion_2 e) {
// gestor de excepciones para TipoExcepcion2
throw (e); // volver a lanzar la excepción
} finally {
}

TipoExcepción_i debe ser el nombre de una clase de la jerarquía de clases inferior o


bien alguna de sus subclases. Suele ser habitual usar la clase Exception. Java tiene
predefinidas varias subclases de Exception que permiten afinar más el tipo de excepción
ocurrido.

La clase Exception se usa para condiciones excepcionales que los programas de usuario

Throwable

Exception Error

RuntimeException

01/03/2002 21/24
Programación Concurrente – Introducción a Java F. Sánchez

deberían capturar. Será pues la clase de partida de las subclases que utilizaremos para
crear nuestras propias condiciones excepcionales y que se espera que otros capturen. La
otra subclase, error, define las condiciones que no deberían ser capturadas en
condiciones normales. Normalmente estas excepciones se crean como respuesta a fallos
catastróficos. Finalmente tenemos la clase RuntimeException para excepciones creadas
por el intérprete como respuesta a fallos del programa.

Try y Catch
Consideremos el siguiente programa. En él se hace una división por 0. Si ejecutamos
esto en Java nos dará un error en tiempo de ejecución y el programa abortará. Para
controlar este tipo de errores es para lo que Java proporciona la gestión de excepciones
que es similar a la de C++.

Class PruebaExcepciones {
public static void main (String args[]) {
int d=0;
int a=42/d;
}
}

El mismo programa pero gestionando la posible excepción que se produzca:

Class PruebaExcepciones2 {
public static void main (String args[]) {
try {
int d=0;
int a=42/d;
} catch (ArithmeticException e) { // se captura la excepción
System.out.println ("division por cero");
}
}
}

ArithmeticException es una clase definida por Java que hereda de Exception.


El ámbito de catch está restringido a las sentencias especificadas por la sentencia try
precedente.
Se permiten cláusulas catch múltiples.
Se permiten sentencias try anidadas.

Throw
Se utiliza para lanzar explícitamente una excepción. En este ejemplo se lanza una
excepción desde el propio try para que sea capturada por catch, donde vuelve a ser
lanzada para que sea recogida por su llamador, en este caso el método main.

class ThrowDemo {
static void demoproc () { // static para poder ser llamado desde main
try {
throw new NullPointerException (“demo”);
} catch (NullPointerException e) {

01/03/2002 22/24
Programación Concurrente – Introducción a Java F. Sánchez

System.out.println (“capturada dentro de demoproc”);


Throw e;
}
}
public static void main (String args[]) {
try {
demoproc();
} catch (NullPointerException e) {
System.out.println (“capturada de nuevo ” + e);
}
}
}

La salida para este programa:


C:\> java ThrowDemo
capturada dentro de demoproc
capturada de nuevo: java.lang.NullPointerException: demo

Throws
Esta palabra clave se utiliza para identificar la lista de excepciones posibles que un
método puede lanzar si es que no las captura él mismo. De esta forma los llamante
pueden protegerse ante tales excepciones. Para exceciones de tipo RunTime y Errors no
hace falta. La cabecera de un método será en este caso:
type nombre-método (lista-args) throws lista-excepciones { }

Un ejemplo:

class ThrowsDemo {
static void procedure () throws IllegalAccessException {
System.out.println ("dentro de procedure");
throw new IllegalAccessException ("demo");
}
public static void main (String args[]) {
try {
procedure ();
}
catch (IllegalAccessException e) {
System.out.println ("capturada "+ e);
}
}
}

La salida para el ejemplo:


C:\>java ThrowsDemo
dentro de procedure
capturada java.lang.IllegalAccessException: demo

Igualmente, en el ejemplo de 0 habría que haber puesto en la cabecera del método


demoproc la cláusula throws NullPointerException.

01/03/2002 23/24
Programación Concurrente – Introducción a Java F. Sánchez

Finally
Siempre que un método vaya a devolver el control al llamante, mediante una excepción
no capturada, o una sentencia return explícita dentro del bloque try, se ejecuta la
cláusula finally justo antes del final del método. Es totalmente opcional.

CREANDO NUESTRAS PROPIAS EXCEPCIONES


Nos podemos crear nuestras propias excepciones y luego utilizarlas como hasta ahora.
Las excepciones que creemos tendrán que heredar de alguna forma de la clase
Exception. En el ejemplo inferior MyException (int a) es el constructor y el método
toString sirve para establecer lo que se va a imprimir cuando se quiere imprimir el
objeto con el método System.out.println.

class MyException extends Exception {


private int detail;
MyException (int a) {
detail =a;
}
public String toString () {
return "MyException["+detail+"]";
}
}

class ExceptionDemo {
static void compute (int a) throws MyException {
System.out.println ("llamada con compute (" +a+ ").");
if (a>10)
throw new MyException (a);
System.out.println ("salida normal.");
}
public static void main (String args[]) {
try {
compute(1);
compute(20);
}
catch (MyException e) {
System.out.println ("capturada "+e);
}
}
}

La salida sería:
llamada con compute (1).
salida normal.
llamada con compute (20).
capturada MyException[20]

01/03/2002 24/24

También podría gustarte