[icono]Manual de Java Volver a índice

Capítulo 5. Paquetes e interfaces.


Paquetes

Los paquetes son los módulos de Java. Recipientes que contienen clases y que se utilizan tanto para mantener el espacio de nombres dividido en compartimentos más manejables como un mecanismo de restricción de visibilidad. Se pueden poner clases dentro de los paquetes restringiendo la accesibilidad a éstas en función de la localización de los otros miembros del paquete. Cada archivo .java tiene las mismas cuatro partes internas y hasta ahora sólo hemos utilizado una de ellas en nuestros ejemplos. Esta es la forma general de un archivo fuente de Java.

una única sentencia de paquete (opcional) las sentencias de importación deseadas (opcional) una única declaración de clase pública las clases privadas de paquete deseadas (opcional)

La sentencia package (paquete)

Lo primero que se permite en un archivo Java es una sentencia package, que le dice al compilador en qué paquete se deberían definir las clases incluidas. Si se omite la sentencia package, las clase terminan en el paquete por defecto, que no tiene nombre. El compilador Java utiliza directorios de sistema de archivos para almacenar paquetes.
Si se declara que una clase está en dentro de un paquete llamado MiPaquete, entonces el archivo fuente de esa clase se debe almacenar en un directorio llamado MiPaquete.
Recuerde que se diferencia entre mayúsculas y minúsculas y que el nombre del directorio debe coincidir con el nombre exactamente. Esta es la forma general de la sentencia package.

package paq1[ .paq2 [ .paq3 ]];

Observe que se puede crear una jerarquía de paquetes dentro de paquetes separando los niveles por puntos. Esta jerarquía se debe reflejar en el sistema de archivos de desarrollo de Java. Un paquete declarado como

package java.awt.imagen;

se debe almacenar en java/awt/imagen, en java\awt\imagen o en java:awt:imagen en los sistemas de archivo UNIX, Windows o Macintosh, respectivamente.

Compilación de clases en paquetes

Cuando se intenta poner una clase en un paquete, el primer problema es que la estructura de directorios debe coincidir con la jerarquía de paquetes exactamente. No se puede renombrar un paquete sin renombrar el directorio en el cual están almacenadas las clases. El otro problema que presenta la compilación es más sutil.
Cuando desee llamar a una clase que se encuentre en un paquete deberá prestar atención a su ubicación en la jerarquía de paquetes. Por ejemplo, se crea una clase llamada PaquetePrueba en un paquete llamado prueba. Para ello se crea el directorio llamado prueba y se pone en él PaquetePrueba.java y se compila. Si intenta ejecutarlo, el intérprete no lo encontrará. Esto se debe a que esta clase se encuentra ahora en un paquete llamado prueba y no nos podemos referir a ella simplemente con PaquetePrueba. sin embargo si es posible referirse a cualquier paquete enumerando su jerarquía de paquetes, separando los paquetes por puntos. Por lo tanto, si intenta ahora ejecutar ahora Java con prueba.PaquetePrueba, el intérprete tampoco lo encontrará.
El motivo de este nuevo fracaso se encuentra en la variable CLASSPATH. Probablemente contenga algo parecido a ".;C:\java\classes" que le dice al intérprete que busque en el directorio de trabajo actual y en el directorio de instalación del Equipo de herramientas de desarrollo de Java estándar. El problema es que no hay un directorio prueba en el directorio de trabajo actual porque usted ya está en el directorio prueba. Tiene dos opciones en este momento: cambiar de directorio un nivel arriba y ejecutar "java prueba.PaquetePrueba", o aņadir el extremo de su jerarquía de clases de desarrollo a la variable de entorno CLASSPATH. Después podrá utilizar "java prueba.PaquetePrueba" desde cualquier directorio y Java encontrará el archivo .class adecuado. Si trabaja con su código fuente en un directorio llamado C:\mijava, dé a CLASSPATH el valor ".;C:\mijava;C:\java\classes".

La sentencia import

Lo siguiente que se pone después de una sentencia package y antes de las definiciones de clase en un archivo fuente en Java puede ser una lista de sentencias import. Todas las clases interesantes están almacenadas en algún paquete con nombre. Para no tener que introducir el largo nombre de trayecto de paquete para cada clase, Java incluye la sentencia import para que se puedan ver ciertas clases o paquetes enteros. La forma general de la sentencia import:

import paquete1.[ paquete2 ].( nombre_clase | * );

paquete1 es el nombre de un paquete de alto nivel, paquete2 es el nombre de un paquete opcional contenido en el paquete exterior separado por un punto (.). No hay ningún límite práctico a la profundidad de la jerarquía de paquetes.
Finalmente, nombre_clase explícito o un asterisco (*) que indica que el compilador Java debería buscar este paquete completo.

import java.util.Date;
import java.io.*;

Protección de accesos

Java proporciona unos cuantos mecanismos para permitir un control de acceso entre clase en circunstancias diferentes.
Dentro de un clase todas las variables y métodos son visibles para todas las otras partes de la misma clase. Por la existencia de paquetes, Java debe distinguir cuatro categorías de visibilidad entre elementos de clase:

	- Subclases del mismo paquete.
	- No subclases del mismo paquete.
	- Subclases en paquetes distintos.
	- Clases que no están ni en el mismo paquete ni en las subclases.

Las tres palabras clave, private, public y protected se combinan de varias maneras para generar muchos niveles de acceso. La tabla siguiente resume las interacciones.

private sin modificador private protected protected public
misma clase
misma subclase de paquete no
misma no subclase de paquete no no
subclase de diferente paquete no no
no subclase de diferente paquete no no no no

Interfaces

Las interfaces de Java están diseņadas para admitir resolución de método dinámica durante la ejecución. Para que un método sea llamado desde una clase a otra, ambas clases tienen que estar presentes durante la compilación, para que el compilador de Java pueda comprobar que las signaturas de método son compatibles. Debe haber un mecanismo para desconectar la definición de un método o conjunto de métodos de la jerarquía de herencias. Las interfaces son como las clases, pero sin variables de instancia y con métodos declarados sin cuerpo. Las clases pueden inplementar varias interfaces. Para implementar una interfaz, todo lo que necesita una clase es una implementación del conjunto completo de métodos de la interfaz. Las interfaces están en una jerarquía distinta de la de las clases, por lo que es posible que varias clases que no tengan la más mínima relación en cuanto a la jerarquía de clases implementen la misma interfaz.

La sentencia interface

La forma general de una interfaz es

interface nombre {
	tipo_devuelto nombre_de_método1(lista_de_parámetros);
	type nombre_var_final = valor;
}

Aquí nombre es cualquier identificador legal. Observe que los métodos que se declaran no tienen sentencias de cuerpo. Todos los métodos que están implementando interfaces se deben declarar como public. Las variables se pueden declarar dentro de las declaraciones de interfaz y son final implícitamente, lo que significa que no las puede cambiar la clase que las implementa y además deben ser inicializadas con un valor constante. Un ejemplo de declaración de interfaz que contiene un método que toma un único parámetro.

interface Callback {
	void callback(int param);
}

La sentencia implements

Ampliando nuestra definición anterior de clase, una clase que implementa algunas interfaces tiene la forma general siguiente.

class nombre_de_clase [extends superclase] [implements interfaz0 [,interfaz1...]] {
	cuerpo_de_clase;
}