Post original escrito por Franciso Charte en campusMVP
Los paquetes son el mecanismo que usa Java para facilitar la modularidad del código. Un paquete puede contener una o más definiciones de interfaces y clases, distribuyéndose habitualmente como un archivo. Para utilizar los elementos de un paquete es necesario importar este en el módulo de código en curso, usando para ello la sentencia import
.
La funcionalidad de una aplicación Java se implementa habitualmente en múltiples clases, entre las que suelen existir distintas relaciones. Las clases se agrupan en unidades de un nivel superior, los paquetes , que actúan como ámbitos de contención de tipos. Cada módulo de código establece, mediante la palabra clave package
al inicio, a qué paquete pertenece. Como ya sabrás, con la cláusula import
cualquier módulo de código puede hacer referencia a tipos definidos en otros paquetes.
Vamos a familiarizarnos con los procedimientos para construir paquetes, para referenciarlos desde otros puntos y también veremos la relación existente entre paquetes, clases y el sistema de archivos donde se almacena el proyecto.
Creación de paquetes
Un paquete Java se genera sencillamente incluyendo la palabra clave package
al inicio de los módulos de código en los que se definen las clases que formarán parte del mismo. Trabajando en un proyecto con NetBeans, comprobaremos que en la ventana Projects
los paquetes se representan con un icono específico y actúan como nodos contenedores, alojando los módulos .java
con el código fuente. El menú contextual del proyecto nos ofrece la opción New>Java Package
, que será el que usemos habitualmente para crear un nuevo paquete:
Nota : cada vez que se crea un nuevo proyecto con NetBeans se propone la definición de un nuevo paquete, cuyo nombre sería el mismo del proyecto, donde se alojarían los módulos de código. En proyectos complejos, no obstante, puede ser necesaria la creación de paquetes adicionales.
Un paquete puede contener, además de definiciones de tipos como las clases e interfaces, otros paquetes, dando lugar a estructuras jerárquicas de contenedores. La denominación de los subpaquetes, paquetes contenidos en otros , se compondrán del identificador del contenedor seguido de un punto y el nombre del subpaquete. De existir niveles adicionales se agregarían los distintos identificadores separados por puntos, formando así el nombre completo del paquete.
El diagrama siguiente representa el contenido de un paquete llamado campusmvp
, teóricamente correspondiente a un proyecto de aplicación de contabilidad. En ese paquete de primer nivel tenemos un subpaquete con utilidades, llamado campusmvp.util
, no directamente vinculadas con la aplicación de contabilidad. El subpaquete campusmvp.conta
contendría todos los elementos asociados a dicha aplicación, distribuidos a su vez en un tercer nivel de paquetes que contienen las clases correspondientes al modelo, la vista, etc., siguiendo al patrón arquitectónico MVC. Cada uno de los módulos de definición de clase, denominados Cuenta.java
, Movimiento.java
, Vista.java
, etc., comenzarían con una cláusula package
indicando el nombre completo del paquete al que pertenecen :
Nota : todas las clases que pertenecen a un mismo paquete comparten un ámbito común, al que pertenecerán aquellos miembros que no especifiquen explícitamente otro tipo de visibilidad.
Importación de paquetes
Los paquetes Java son como cajas de herramientas , cada una de ellas con una colección distinta de instrumentos útiles para nuestro trabajo, a las que podemos necesitar acceder cada vez que abordamos el desarrollo de un nuevo proyecto. Es en este contexto donde recurriremos a la cláusula import
, a fin de importar en el ámbito actual las definiciones de otro paquete y poder usarlas según el procedimiento habitual, creando objetos, accediendo a los servicios de las clases, etc.
La cláusula import
puede utilizarse para importar un elemento concreto de un paquete, facilitando el nombre de este seguido de un punto y el identificador de dicho elemento. Por ejemplo, para importar la clase Math
del paquete java.lang
, pudiendo así acceder a la constante PI
y las funciones matemáticas que aporta, bastaría con la siguiente línea:
import java.lang.Math;
Es habitual que al importar un paquete nos interesen muchas de las clases definidas en el mismo. En este caso podríamos importarlas individualmente, usando la sintaxis anterior, o bien podríamos recurrir a la siguiente alternativa. Esto nos permitiría usar la clase Math
, así como la clase System
, la clase Thread
y muchas otras definidas en el paquete java.lang
:
import java.lang.\*;
En ocasiones, como ocurre con la clase Math
, importamos una clase para acceder directamente a sus miembros estáticos, constantes y métodos , no para crear objetos a partir de ellas, lo que nos fuerza a utilizar constantemente la sintaxis Clase.miembro
, por ejemplo Math.PI
o Math.sin()
. Si tras importar la clase Math
intentamos referirnos a estos miembros simplemente por su nombre, como se hace en la mitad superior de la siguiente imagen, obtendremos un error. En estos casos podemos recurrir a la sintaxis import static paquete.clase.*
, cuya finalidad es incluir en el ámbito actual los miembros estáticos de la clase indicada. Es lo que se hace en la mitad inferior de la siguiente imagen:
Relación entre clases, paquetes y el sistema de archivos
En Java existe una estrecha relación entre las definiciones de paquetes y clases y el sistema de archivos local , en el que se almacenan los módulos conteniendo el código. Es un hecho que puede pasarnos totalmente inadvertido al trabajar con un IDE como el de NetBeans, ya que sus opciones se encargan de ocultar estos detalles. No obstante, es interesante que conozcamos dicha relación ya que esto nos permitirá, en caso de necesidad, trabajar directamente con el JDK.
Cada módulo de código de un proyecto Java únicamente puede contener una clase pública, cuyo nombre, respetando mayúsculas y minúsculas, debe coincidir con el del módulo. Es decir, existe una correspondencia directa entre los identificadores de clase y archivos en los que se alojan. Esto no afecta a las clases anidadas y otras clases no públicas que pudiesen definirse en el mismo módulo.
El nombre del paquete establece además el nombre de la carpeta donde se alojan los módulos de código contenidos en el paquete. Los nombres de paquete pueden ser compuestos, usándose el punto como separador de las diferentes porciones del identificador. Cada parte identificaría a un subdirectorio, según se muestra en el siguiente esquema:
Al trabajar desde la línea de comandos, usando directamente el JDK, hemos de tener en cuenta que tanto la compilación como la ejecución verificarán que se satisface la correspondencia entre el nombre de paquete y clase y la estructura de directorios y nombre de archivo. Si esta no se cumple en algún punto, como ocurre en la parte inferior de la siguiente imagen, se obtiene un error.
Nota : la estructura de directorios de un paquete puede almacenarse completa, una vez se compila el proyecto, en un archivo JAR. Este contendría asimismo los archivos de clase de cada módulo de código.
A continuación puedes ver un vídeo práctico explicativo de todo lo anterior, que está extraído directamente del curso de programación con Java de campusMVP:
Post original escrito por Franciso Charte en campusMVP
Top comments (0)