Organizar el código: packages e imports
Cuando cada clase vive en su archivo, una carpeta plana deja de explicar el sistema. Los packages agrupan tipos relacionados y evitan conflictos de nombres.
La estructura y el nombre deben coincidir
Crearemos este proyecto:
src/
├── app/
│ └── Main.java
├── modelo/
│ └── Alumno.java
└── servicio/
└── Informe.java
La primera línea de cada archivo declara su package. La ruta refleja ese nombre.
src/modelo/Alumno.java:
package modelo;
public class Alumno {
private String nombre;
public Alumno(String nombre) {
this.nombre = nombre;
}
public String getNombre() {
return nombre;
}
}
Una clase usada desde otro package debe ser accesible; por eso Alumno y su constructor son public.
Importar un tipo
src/servicio/Informe.java:
package servicio;
import modelo.Alumno;
public class Informe {
public String generar(Alumno alumno) {
return "Informe de " + alumno.getNombre();
}
}
import modelo.Alumno permite usar el nombre corto Alumno. El import no copia código ni crea objetos: solo indica qué tipo significa ese nombre.
Punto de entrada
src/app/Main.java:
package app;
import modelo.Alumno;
import servicio.Informe;
public class Main {
public static void main(String[] args) {
Alumno alumno = new Alumno("Nuria");
Informe informe = new Informe();
System.out.println(informe.generar(alumno));
}
}
Las clases de java.lang, como String y System, se importan automáticamente. Para otros packages de la biblioteca estándar normalmente escribiremos el import explícito.
Compilar respetando los packages
Desde la raíz del proyecto:
mkdir out
javac -d out src/modelo/Alumno.java src/servicio/Informe.java src/app/Main.java
java -cp out app.Main
-d out pide a javac que genere los .class bajo la estructura adecuada. -cp out indica dónde buscarlos. El nombre ejecutado es app.Main, no una ruta ni Main.java.
Salida:
Informe de Nuria
Nombre completamente cualificado
También podemos escribir el nombre completo sin import:
modelo.Alumno alumno = new modelo.Alumno("Nuria");
Resulta útil para resolver dos tipos con el mismo nombre, pero abusar de ello hace el código ruidoso. Los imports explícitos suelen ser más legibles.
Visibilidad de package
Un miembro o clase sin modificador es package-private: solo está disponible dentro del mismo package.
class FormateadorInterno {
String limpiar(String texto) {
return texto.trim();
}
}
Puede servir como detalle interno de servicio, pero app.Main no podría usarlo. No es lo mismo que private, que limita el acceso a la propia clase.
Errores habituales
- Declarar
package modelo;en un archivo colocado en otra ruta. - Ejecutar
java Maincuando la clase pertenece aapp. - Confundir importar con instalar una dependencia.
- hacer pública cada clase aunque solo sea un detalle interno.
- Usar
import modelo.*para ocultar qué tipos necesita el archivo.
Practica: catálogo organizado
Enunciado y criterios
Organiza Producto, Etiqueta, EtiquetaSimple y Main: modelo contiene Producto, servicio contiene el contrato y su implementación, y app crea e imprime un producto. Usa imports explícitos, una ruta coherente y un comando reproducible.
Solución
src/modelo/Producto.java
src/servicio/Etiqueta.java
src/servicio/EtiquetaSimple.java
src/app/Main.java
Producto.java:
package modelo;
public class Producto {
private String nombre;
public Producto(String nombre) { this.nombre = nombre; }
public String getNombre() { return nombre; }
}
Etiqueta.java:
package servicio;
import modelo.Producto;
public interface Etiqueta {
String crear(Producto producto);
}
Main.java:
package app;
import modelo.Producto;
import servicio.Etiqueta;
import servicio.EtiquetaSimple;
public class Main {
public static void main(String[] args) {
Producto producto = new Producto("Teclado");
Etiqueta etiqueta = new EtiquetaSimple();
System.out.println(etiqueta.crear(producto));
}
}
EtiquetaSimple.java:
package servicio;
import modelo.Producto;
public class EtiquetaSimple implements Etiqueta {
@Override public String crear(Producto producto) { return producto.getNombre(); }
}
Desde la raíz del proyecto, compila los cuatro archivos y ejecuta app.Main:
mkdir out
javac -d out \
src/modelo/Producto.java \
src/servicio/Etiqueta.java \
src/servicio/EtiquetaSimple.java \
src/app/Main.java
java -cp out app.Main
La salida será Teclado. Organizar packages no exige anticipar herramientas ni sintaxis de cursos posteriores.
La organización ya permite que el proyecto final crezca sin mezclar modelo, servicios y entrada de la aplicación.