|
| Volver a índice |
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".
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.*;
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 | sí | sí | sí | sí | sí |
| misma subclase de paquete | no | sí | sí | sí | sí |
| misma no subclase de paquete | no | sí | no | sí | sí |
| subclase de diferente paquete | no | no | sí | sí | sí |
| no subclase de diferente paquete | no | no | no | no | sí |
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 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);
}
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;
}