Saltar a contenido

3. Estructura de un programa Java

Ficha de la sección

Campo Valor
Unidad de Programación UD1 — Fundamentos de Programación
Resultado de Aprendizaje RA1 — Reconoce la estructura de un programa informático, identificando y relacionando los elementos propios del lenguaje de programación utilizado
Duración orientativa Aproximadamente 4 de las 28 horas totales de UD1
Criterios de Evaluación implicados CE 1.1 (Se han identificado los bloques que componen la estructura de un programa informático) como criterio principal, y CE 1.9 (Se han introducido comentarios en el código)
Encaja en el roadmap Es el momento en el que la teoría de la Sección 1 (programa, algoritmo, instrucción) y las herramientas de la Sección 2 (IntelliJ, Maven) se encuentran por primera vez con sintaxis Java real. A partir de aquí, todas las unidades del curso dan por hecho que sabes leer y montar el esqueleto de cualquier clase Java

Antes de empezar

Ya tienes el taller montado (IntelliJ) y el motor conectado (JDK 25 vía Maven). Toca abrir el capó y mirar, pieza a pieza, qué hay dentro de un programa Java. Y aquí viene la buena noticia: no vas a aprender nada nuevo desde cero, vas a ponerle sintaxis a algo que ya entiendes.

¿Recuerdas la jerarquía de la Sección 1? Programa → Algoritmo → Instrucción, como un recetario, sus recetas y los pasos de cada receta. Pues bien: en Java, esa misma jerarquía tiene nombre y apellido.

flowchart TB
    subgraph CLASS["class HolaMundo { }   —   tu PROGRAMA (el contenedor obligatorio)"]
        direction TB
        subgraph MAIN["public static void main(String[] args) { }   —   tu ALGORITMO principal (la puerta de entrada)"]
            direction TB
            L1["Instrucción: System.out.println(...);"]
            L2["Instrucción: System.out.println(...);"]
            L3["Instrucción: ..."]
        end
    end

    style CLASS fill:#e3f2fd,stroke:#1565c0
    style MAIN fill:#e8f5e9,stroke:#2e7d32

La clase es tu programa (el contenedor obligatorio). El método main es, de momento, tu algoritmo principal (la puerta de entrada por la que todo empieza). Y cada línea de código dentro de él es una instrucción. Vamos a diseccionar cada pieza.


3.1. La clase como contenedor obligatorio

En Java, todo el código que escribas (con una única excepción que veremos en el apartado 3.3) tiene que vivir dentro de una clase. No existe la posibilidad de escribir instrucciones "sueltas" a nivel del fichero, como sí ocurre en otros lenguajes. La clase es el envoltorio obligatorio: nada se ejecuta sin estar dentro de una.

1
2
3
public class HolaMundo {
    // todo tu código vive aquí dentro
}
Palabra Qué significa ¿Se puede cambiar?
public Modificador de acceso: esta clase es visible desde cualquier otro fichero o paquete del proyecto Sí existen otras opciones (las verás en profundidad en UD4), pero por ahora usaremos siempre public
class Palabra reservada del lenguaje: declara que lo que sigue es una clase No, es una palabra fija del lenguaje
HolaMundo El nombre que tú eliges para tu clase Sí, lo eliges tú, pero con una regla estricta (ver aviso siguiente)
{ } Delimitan el cuerpo de la clase: todo lo que "vive dentro" de ella Las llaves son obligatorias; su contenido, no

Regla estricta que causa muchos primeros errores. Si una clase se declara public, su nombre debe coincidir exactamente (mayúsculas incluidas) con el nombre del fichero que la contiene. Es decir, la clase public class HolaMundo solo puede vivir en un fichero llamado HolaMundo.java. Si el fichero se llamara holamundo.java o Hola_Mundo.java, el compilador se negaría a compilar. No es una sugerencia de estilo: es una exigencia del compilador.


3.2. El método main: el punto de entrada del programa

Cuando ejecutas un programa Java (con mvn exec:java, con Shift + F10 en IntelliJ, o directamente con el comando java), la JVM no empieza a leer tu clase de arriba abajo como si fuera una novela. Busca, de forma muy concreta, un método con una firma exacta: main. Si no lo encuentra, no hay programa que ejecutar.

flowchart LR
    JVM["La JVM arranca\ny busca..."] --> SEARCH{"¿Existe un método\npublic static void main(String[] args)?"}
    SEARCH -->|Sí| RUN["Empieza a ejecutar\nel programa desde ahí"]
    SEARCH -->|No| ERROR["Error:\n'Main method not found'"]

    style JVM fill:#1565c0,color:#fff,stroke:#0d47a1
    style RUN fill:#2e7d32,color:#fff,stroke:#1b5e20
    style ERROR fill:#b71c1c,color:#fff,stroke:#7f0000

Vamos a diseccionar su firma completa, palabra por palabra, porque cada una está ahí por una razón concreta (aunque algunas las entenderás del todo más adelante):

1
2
3
public static void main(String[] args) {
    // el punto exacto donde empieza tu programa
}
Palabra Qué significa ¿Por qué está ahí?
public El método debe ser accesible desde fuera de la clase Si fuera private, la JVM no podría "verlo" ni llamarlo desde fuera
static El método pertenece a la clase en sí misma, no a un objeto creado a partir de ella La JVM tiene que poder llamarlo antes de que exista ningún objeto de tu clase. Profundizaremos en static en UD4
void El método no devuelve ningún valor El programa simplemente se ejecuta y termina; no "retorna" un resultado a nadie
main El nombre exacto y fijo que la JVM busca como punto de entrada Es un contrato del lenguaje: si lo llamas Main, principal o cualquier otra cosa, la JVM no lo encontrará
String[] args Un array de textos con los argumentos que se pasen al ejecutar el programa desde la línea de comandos Lo usarás más adelante; de momento puede quedarse vacío sin ningún problema

Nota para el aula. No memorices estas palabras como un conjuro mágico. public static void main(String[] args) no es una fórmula que "hay que poner sí o sí sin preguntar": es una firma con significado propio, palabra por palabra, y en unas semanas (cuando lleguemos a UD4 y entiendas static a fondo, o a UD2 cuando trabajes con arrays) todas las piezas encajarán del todo. Por ahora, con la tabla anterior tienes más que suficiente para defenderte con soltura.


3.3. Unnamed classes e instance main methods (Java 25, estables)

Aquí viene una de las novedades más interesantes de Java moderno, y también la única excepción a la regla de "todo vive dentro de una clase" que hemos visto en el punto 3.1.

Desde hace unas versiones, Java ha ido incorporando (primero como funcionalidad de vista previa, y ya estabilizada en Java 25) una forma simplificada de escribir un primer programa, pensada explícitamente para quitar barreras de entrada a quien empieza a programar. En vez de exigir clase pública, static y toda la ceremonia que acabas de ver, te permite escribir directamente esto:

1
2
3
4
5
// Forma simplificada (unnamed class + instance main method).
// No hay "package", no hay "public class", no hay "static".
void main() {
    System.out.println("Hola, mundo");
}

¿Qué ha pasado con la clase? No ha desaparecido: el compilador genera por debajo, de forma automática, una clase sin nombre que envuelve este código. Es decir, la regla de "todo vive dentro de una clase" se sigue cumpliendo, simplemente ya no tienes que escribirla tú a mano.

Forma clásica Forma simplificada (Java 25)
Palabras clave necesarias public class NombreClase, y static en el main Ninguna: solo void main() { }
¿El nombre de la clase debe coincidir con el fichero? Sí, siempre No aplica: el compilador crea una clase sin nombre
¿Se puede declarar package? Sí, y lo usaremos siempre en este curso No: las unnamed classes viven en el paquete sin nombre
¿Cuándo la usaremos en este módulo? Siempre que trabajemos dentro de un proyecto Maven, es decir, casi siempre Solo como apoyo puntual para entender qué simplifica y por qué
Pensada para... Aplicaciones reales, con varias clases organizadas en paquetes Quien empieza a programar, ejemplos de una sola clase, scripts rápidos de una sesión

Dato clave y decisión pedagógica de este curso. En este módulo trabajaremos siempre en proyectos Maven, con paquetes (dam.programacion.udX), tal y como viste en la Sección 2. Como las unnamed classes no admiten package, la forma simplificada no encaja bien con esa forma de trabajar profesional que queremos que interiorices desde ya. Por eso usaremos la forma clásica (public class + static) como estándar durante todo el curso. Aun así, era importante que conocieras esta forma simplificada por dos motivos: la vas a encontrar en tutoriales y documentación moderna, y te ayuda a entender qué hace realmente cada palabra de la forma clásica, viendo qué ocurre cuando se quitan.


3.4. Salida por consola: println, printf y print

Para que un programa sirva de algo, necesita comunicarse contigo. La forma más básica es escribir texto en la consola, y Java te da tres métodos para hacerlo, cada uno con un matiz distinto:

1
2
3
System.out.println("Esto imprime el texto y salta de línea al terminar");
System.out.print("Esto imprime el texto SIN saltar de línea");
System.out.printf("Nota media: %.2f%n", 8.5);
Método ¿Salta de línea al terminar? Cuándo lo usarás
System.out.println(...) Sí, automáticamente La opción por defecto: mostrar un valor y pasar a la siguiente línea
System.out.print(...) No Cuando quieres que la siguiente instrucción continúe escribiendo en la misma línea
System.out.printf(...) No, salvo que incluyas %n explícitamente Cuando necesitas dar formato preciso al texto (decimales, anchura de columnas...). Le sacaremos todo el partido en UD5

Dato clave. %n en printf representa un salto de línea "independiente del sistema operativo" (en Windows es distinto internamente que en Linux/macOS, y %n se adapta solo). Es preferible a escribir \n a mano cuando usas printf, aunque \n también funciona y lo verás con frecuencia.


3.5. Sensibilidad a mayúsculas, punto y coma, y bloques { }

Java es, en esto, un lenguaje extremadamente estricto y nada tolerante con la ambigüedad, exactamente como ya anticipamos en la Sección 1 al hablar de qué significa programar. Tres reglas que no admiten excepciones:

  1. Java distingue mayúsculas de minúsculas (case-sensitive). System, system y SYSTEM son tres identificadores completamente distintos para el compilador. No hay margen de interpretación.
  2. Cada instrucción termina en punto y coma ;. El punto y coma le dice al compilador "aquí termina esta orden". Sin él, el compilador no sabe dónde acaba una instrucción y dónde empieza la siguiente.
  3. Los bloques de código se delimitan con llaves { }. Toda clase y todo método necesitan sus llaves de apertura y cierre. Un desajuste en el número de llaves suele arrastrar errores de compilación confusos a líneas que, en realidad, están bien escritas.
Error típico Ejemplo Por qué falla
Olvidar el punto y coma System.out.println("Hola") sin ; al final El compilador no sabe dónde termina la instrucción
Confundir mayúsculas y minúsculas Escribir system.out.println(...) en vez de System.out.println(...) system (minúscula) no existe; es un identificador distinto de System
Llaves { } descuadradas Abrir una llave y olvidar cerrarla más adelante El compilador arrastra el error, a veces señalando una línea muy posterior que en realidad está bien escrita
Nombre de clase distinto al del fichero Clase public class Main guardada en un fichero HolaMundo.java El compilador exige que coincidan exactamente cuando la clase es public

Nota para el aula. El primer día que el compilador te señale un error "en la línea 47" cuando tu error real está en la línea 12 (por una llave { que te dejaste sin cerrar), vas a dudar de tu cordura. Es de lo más normal del mundo: el compilador interpreta el código según las reglas que le has dado, y si desde la línea 12 "algo queda abierto", arrastra la confusión hasta donde puede. IntelliJ te ayuda mucho aquí resaltando visualmente las llaves que hacen pareja; apóyate en esa ayuda visual sin remordimientos.


3.6. Comentarios: //, /* */ y Javadoc /** */

Los comentarios son texto que escribes en tu código pero que el compilador ignora por completo: no forman parte del programa, son notas para los humanos que lean ese código (incluido tú mismo, dentro de seis meses, cuando ya no recuerdes por qué escribiste algo de una forma concreta).

// Comentario de una línea: para aclaraciones rápidas y puntuales

/*
 * Comentario de bloque: para explicaciones más largas
 * que ocupan varias líneas, o para desactivar temporalmente
 * varias líneas de código sin borrarlas
 */

/**
 * Comentario Javadoc: además de documentar, esta herramienta
 * permite generar documentación HTML automáticamente con el
 * comando "javadoc". Le sacaremos partido a fondo a partir de UD2.
 *
 * @author Nombre del alumno
 */
public class HolaMundo {
    // el resto de tu código
}
Tipo Sintaxis Para qué se usa
De línea // comentario Aclaraciones puntuales y muy cortas
De bloque /* ... */ Explicaciones más largas, o para anular temporalmente varias líneas de código
Javadoc /** ... */ Documentación oficial de clases y métodos, exportable como HTML con la herramienta javadoc

Buena práctica desde el primer día. Un comentario útil explica el por qué, no el qué. Comentar i++; // incrementa i en uno es ruido: cualquiera que sepa Java ya ve que i++ incrementa i. En cambio, un comentario como // se empieza en 1 y no en 0 porque el primer trimestre del ciclo no se numera sí aporta información que el código, por sí solo, no cuenta. Los comentarios que solo repiten lo obvio envejecen mal: en cuanto el código cambia, el comentario suele quedarse desactualizado y mentir descaradamente sobre lo que el programa hace de verdad.


3.7. Convenciones de nomenclatura Java

Java tiene convenciones de estilo muy asentadas en toda su comunidad, hasta el punto de que IntelliJ te avisará (con un subrayado amarillo) si las rompes. No son caprichos: permiten que cualquier programador Java del mundo, al leer tu código, sepa de un vistazo si algo es una clase, una variable o una constante, sin necesidad de mirar su declaración.

Convención Se usa para... Ejemplos
PascalCase (cada palabra empieza en mayúscula, incluida la primera) Nombres de clases HolaMundo, CuentaBancaria, GestorNotas
camelCase (la primera palabra en minúscula, el resto con mayúscula inicial) Variables y métodos notaMedia, numeroAlumnos, calcularNotaMedia()
UPPER_SNAKE_CASE (todo en mayúsculas, palabras separadas por guion bajo) Constantes (static final) NOTA_MAXIMA, IVA_GENERAL, DIAS_SEMANA
minúsculas, sin guiones Nombres de paquete dam.programacion.ud1
flowchart TD
    N["Nombra algo en Java"] --> Q{"¿Qué es?"}
    Q -->|Una clase| PC["PascalCase\nHolaMundo"]
    Q -->|Una variable o método| CC["camelCase\nnotaMedia"]
    Q -->|Una constante| UC["UPPER_SNAKE_CASE\nNOTA_MAXIMA"]
    Q -->|Un paquete| PKG["minúsculas.sin.guiones\ndam.programacion.ud1"]

    style PC fill:#1565c0,color:#fff,stroke:#0d47a1
    style CC fill:#2e7d32,color:#fff,stroke:#1b5e20
    style UC fill:#e65100,color:#fff,stroke:#bf360c
    style PKG fill:#6a1b9a,color:#fff,stroke:#4a148c

Nota para el aula. Estas convenciones no las inventa cada programador a su gusto: están recogidas en las Java Code Conventions originales y asumidas por toda la comunidad desde hace más de 25 años. Adoptarlas desde tu primera línea de código no es un capricho estético: es lo que hace que tu código "se lea como Java" y que cualquier compañero, o cualquier entrevistador técnico, lo reconozca como código escrito por alguien que sabe lo que hace.


Programa completo: todas las piezas juntas

Vamos a cerrar la sección reuniendo, en un único fichero real, todo lo que hemos visto: paquete, Javadoc, clase, constante con nomenclatura correcta, método main, variable local con nomenclatura correcta, y varias formas de salida por consola.

package dam.programacion.ud1;

/**
 * Primer programa completo de la Unidad 1.
 * Reúne todo lo trabajado en la Sección 3: clase como contenedor,
 * método main, salida por consola, comentarios y nomenclatura correcta.
 *
 * @author Alumno o alumna de DAM
 */
public class HolaMundo {

    // Constante de clase: nomenclatura UPPER_SNAKE_CASE
    static final String SALUDO = "Hola";

    public static void main(String[] args) {
        // Variable local: nomenclatura camelCase
        String nombreCiclo = "Desarrollo de Aplicaciones Multiplataforma";

        System.out.println(SALUDO + ", futuro/a programador/a de " + nombreCiclo);
        System.out.printf("Este mismo fichero, compilado una vez, se ejecuta en cualquier sistema operativo.%n");
    }
}

Resumen de la sección

Idea clave En una frase
Clase El contenedor obligatorio de todo el código Java; su nombre debe coincidir con el del fichero si es public
Método main El punto de entrada fijo que la JVM busca para empezar a ejecutar el programa
Unnamed classes / instance main Forma simplificada (Java 25) sin clase explícita ni static; útil para entender, no la usaremos como estándar en este curso
println / print / printf Salida por consola con salto de línea, sin salto de línea, o con formato preciso
Case sensitivity, ;, { } Java no perdona ambigüedades: mayúsculas y minúsculas son distintas, cada instrucción lleva su punto y coma, cada bloque sus llaves
Comentarios // para líneas sueltas, /* */ para bloques, /** */ (Javadoc) para documentación generable
Nomenclatura PascalCase (clases), camelCase (variables y métodos), UPPER_SNAKE_CASE (constantes), minúsculas (paquetes)

Comprueba lo que has entendido

  1. Si tienes una clase public class GestorNotas, ¿cómo se debe llamar obligatoriamente el fichero que la contiene?
  2. ¿Por qué la JVM no podría ejecutar un método main declarado como private?
  3. ¿Qué diferencia real hay entre la forma clásica de main y la forma simplificada de unnamed class, y por qué en este curso usaremos casi siempre la clásica?
  4. Clasifica estos tres identificadores según la convención de nomenclatura que les correspondería: una clase para gestionar alumnos, una variable para guardar la nota media, una constante para el número máximo de créditos.

Qué viene ahora

Ya sabes leer y montar el esqueleto completo de cualquier clase Java: contenedor, punto de entrada, salida por consola, comentarios y nomenclatura correcta. En la Sección 4 de UD1 vamos a meternos dentro de esas instrucciones para trabajar con variables y tipos primitivos: los ocho tipos básicos de Java, cómo declararlos e inicializarlos, la inferencia con var, y los literales numéricos modernos como el separador _ o los formatos hexadecimal y binario.