📦 ¿Qué es una declaración de clase?
En Java, todo programa se construye a partir de clases. Una declaración de clase es la definición formal que establece qué datos almacena un tipo de objeto (sus campos o atributos) y qué operaciones puede realizar (sus métodos). Se trata del bloque de construcción fundamental de la programación orientada a objetos en Java.
Cuando se escribe una declaración de clase, se está creando un nuevo tipo de dato en el lenguaje. A partir de ese tipo, se pueden instanciar tantos objetos como se necesiten mediante el operador new. Cada objeto tendrá su propia copia de los campos de instancia, pero compartirá la definición de los métodos.
Veamos una clase sencilla llamada Publicacion que podríamos utilizar para almacenar los datos de una colección bibliográfica:
public class Publicacion { // Campos (atributos) int idPublicacion; String titulo; String autor; }
Con esta declaración, Publicacion se convierte en un tipo válido en Java. Ahora se pueden crear referencias y objetos de ese tipo:
Publicacion miLibro; // Referencia (aún sin objeto) miLibro = new Publicacion(); // Instanciación del objeto miLibro.titulo = "El Quijote"; // Acceso al campo System.out.println(miLibro.titulo); // El Quijote
📝 Sintaxis básica de una clase
La estructura general de una declaración de clase en Java sigue este patrón:
// Estructura general de una clase en Java [modificador_acceso] [modificadores] class NombreClase [extends SuperClase] [implements Interfaz1, Interfaz2] { // 1. Campos (variables de instancia y de clase) // 2. Constructores // 3. Métodos // 4. Clases internas (opcional) }
Cada componente tiene un propósito específico:
| Componente | Obligatorio | Descripción |
|---|---|---|
modificador_acceso |
No | public, default (sin modificador). Determina la visibilidad de la clase. |
modificadores |
No | abstract, final, strictfp. Modifican el comportamiento de la clase. |
class NombreClase |
Sí | Palabra clave class seguida del nombre. Debe ser un identificador válido y empezar por mayúscula. |
extends SuperClase |
No | Indica de qué clase hereda. Si se omite, hereda implícitamente de Object. |
implements Interfaces |
No | Lista de interfaces que la clase se compromete a implementar. |
Cuerpo { } |
Sí | Contiene campos, constructores, métodos y clases internas. |
▶️ Ejemplo mínimo
La clase más simple posible en Java contiene solo la palabra clave class, un nombre y un cuerpo vacío:
class Vacia { // Clase válida aunque sin contenido }
Aunque legal, una clase vacía no tiene utilidad práctica. En los siguientes apartados se detallan los elementos que la convierten en una herramienta útil.
🗂️ Campos (atributos) de una clase
Los campos (fields), también llamados variables de instancia o atributos, representan el estado de cada objeto. Se declaran dentro del cuerpo de la clase, fuera de cualquier método.
🔹 Declaración de un campo
[modificador_acceso] [modificadores] tipo nombreCampo [= valorInicial];
🔹 Ejemplo con varios campos
public class Vehiculo { // Campos de instancia private String marca; private String modelo; private int anio; private double velocidadActual = 0.0; // Valor inicial explícito private boolean encendido = false; // Valor inicial explícito }
🔹 Valores por defecto de los campos
Si no se asigna un valor explícito, Java inicializa los campos de instancia con valores predeterminados:
| Tipo | Valor por defecto |
|---|---|
byte, short, int, long | 0 |
float, double | 0.0 |
char | '\u0000' |
boolean | false |
Referencias a objetos (String, arrays, etc.) | null |
⚙️ Métodos de una clase
Los métodos definen el comportamiento de los objetos. Se declaran dentro de la clase y pueden acceder a todos los campos del objeto (incluyendo los privados) mediante la referencia implícita this.
▶️ Firma de un método
[modificador_acceso] [modificadores] tipoRetorno nombreMetodo([parámetros]) [throws excepciones] { // Cuerpo del método }
▶️ Clase con campos y métodos
public class Rectangulo { private double ancho; private double alto; public Rectangulo(double ancho, double alto) { this.ancho = ancho; this.alto = alto; } public double calcularArea() { return ancho * alto; } public double calcularPerimetro() { return 2 * (ancho + alto); } public String describir() { return "Rectángulo " + ancho + "x" + alto + " | Área: " + calcularArea() + " | Perímetro: " + calcularPerimetro(); } }
calcularArea(), obtenerNombre(), estaActivo(). Esto mejora la legibilidad del código.🔧 Constructores
Un constructor es un bloque de código especial que se ejecuta automáticamente cuando se crea un objeto con new. Su misión es inicializar el estado del objeto, asignando valores a los campos de instancia.
🔹 Reglas de los constructores
Un constructor se distingue de un método normal por tres características: su nombre es idéntico al de la clase, no tiene tipo de retorno (ni siquiera void) y se invoca exclusivamente a través del operador new.
🔹 Constructor por defecto
Si no se declara ningún constructor, el compilador genera uno automáticamente sin parámetros que inicializa los campos con sus valores por defecto. Sin embargo, en cuanto se declara cualquier constructor (con o sin parámetros), el compilador deja de proporcionar el constructor por defecto.
🔹 Sobrecarga de constructores
Es habitual declarar varios constructores con distintas combinaciones de parámetros para ofrecer flexibilidad al instanciar objetos:
public class Libro { private String titulo; private String autor; private int paginas; // Constructor completo public Libro(String titulo, String autor, int paginas) { this.titulo = titulo; this.autor = autor; this.paginas = paginas; } // Constructor parcial (delega en el completo) public Libro(String titulo, String autor) { this(titulo, autor, 0); // Llama al constructor de 3 parámetros } // Constructor sin parámetros public Libro() { this("Sin título", "Desconocido", 0); } }
this(...) a otro constructor de la misma clase debe ser la primera instrucción del constructor. No se puede colocar después de otras sentencias.⚡ Miembros estáticos (static)
Los miembros declarados con la palabra clave static pertenecen a la clase en su conjunto y no a ninguna instancia individual. Existen en memoria independientemente de que se hayan creado objetos o no.
🔹 Campos estáticos
Un campo estático es compartido por todas las instancias de la clase. Se utiliza comúnmente para contadores, constantes de configuración o valores que no varían entre objetos.
public class Empleado { private static int contadorEmpleados = 0; // Compartido por todos private int id; private String nombre; public Empleado(String nombre) { contadorEmpleados++; this.id = contadorEmpleados; this.nombre = nombre; } public static int getTotalEmpleados() { return contadorEmpleados; } } // Uso: Empleado e1 = new Empleado("Ana"); // contadorEmpleados = 1 Empleado e2 = new Empleado("Carlos"); // contadorEmpleados = 2 System.out.println(Empleado.getTotalEmpleados()); // 2
🔹 Constantes con static final
La combinación static final declara una constante de clase: un valor que no cambia y es compartido por todas las instancias. Por convención, se escribe en MAYÚSCULAS con guiones bajos:
public class Configuracion { public static final int MAX_INTENTOS = 3; public static final double IVA = 0.21; public static final String VERSION = "2.5.1"; } // Acceso directo por el nombre de la clase: System.out.println(Configuracion.MAX_INTENTOS); // 3
📐 Convenciones de nomenclatura
Java tiene convenciones de nomenclatura ampliamente aceptadas que mejoran la legibilidad del código y facilitan la colaboración entre desarrolladores:
| Elemento | Convención | Ejemplo |
|---|---|---|
| Clase | PascalCase (empieza con mayúscula, sustantivo) | CuentaBancaria, Vehiculo |
| Campo / Variable | camelCase (empieza con minúscula) | saldoActual, nombreCompleto |
| Método | camelCase (verbo como primera palabra) | calcularTotal(), getNombre() |
| Constante | MAYUSCULAS_CON_GUIONES | MAX_VALOR, PI |
| Paquete | todo en minúsculas, dominio invertido | com.empresa.proyecto |
.java debe coincidir exactamente con el nombre de la clase, incluyendo mayúsculas: CuentaBancaria.java contiene public class CuentaBancaria.🏗️ Ejemplo completo integrador
El siguiente programa simula un sistema de gestión de una biblioteca. Integra todos los conceptos: campos con encapsulamiento, constructores sobrecargados, métodos de instancia y estáticos, y constantes.
public class Publicacion { // Constante de clase public static final int MAX_TITULO = 200; // Campo estático: contador global private static int totalPublicaciones = 0; // Campos de instancia private int id; private String titulo; private String autor; private int anioPublicacion; private boolean disponible; // Constructor completo public Publicacion(String titulo, String autor, int anioPublicacion) { if (titulo == null || titulo.isBlank()) { throw new IllegalArgumentException("El título no puede estar vacío"); } if (titulo.length() > MAX_TITULO) { throw new IllegalArgumentException("Título demasiado largo"); } totalPublicaciones++; this.id = totalPublicaciones; this.titulo = titulo.trim(); this.autor = (autor != null) ? autor.trim() : "Anónimo"; this.anioPublicacion = anioPublicacion; this.disponible = true; } // Constructor parcial public Publicacion(String titulo, String autor) { this(titulo, autor, 0); } // Getters public int getId() { return id; } public String getTitulo() { return titulo; } public String getAutor() { return autor; } public int getAnioPublicacion() { return anioPublicacion; } public boolean isDisponible() { return disponible; } // Métodos de negocio public void prestar() { if (!disponible) { System.out.println("'" + titulo + "' ya está prestado."); return; } disponible = false; System.out.println("Prestado: " + titulo); } public void devolver() { disponible = true; System.out.println("Devuelto: " + titulo); } // Método estático public static int getTotalPublicaciones() { return totalPublicaciones; } @Override public String toString() { return "[#" + id + "] " + titulo + " (" + autor + ", " + anioPublicacion + ")" + (disponible ? " - Disponible" : " - Prestado"); } }
public class Biblioteca { public static void main(String[] args) { Publicacion p1 = new Publicacion("El Quijote", "Cervantes", 1605); Publicacion p2 = new Publicacion("Effective Java", "Joshua Bloch", 2018); Publicacion p3 = new Publicacion("Clean Code", "Robert C. Martin"); System.out.println("=== Catálogo ==="); System.out.println(p1); System.out.println(p2); System.out.println(p3); System.out.println("\nTotal publicaciones: " + Publicacion.getTotalPublicaciones()); p1.prestar(); p1.prestar(); // Intento duplicado p1.devolver(); } } // Salida esperada: // === Catálogo === // [#1] El Quijote (Cervantes, 1605) - Disponible // [#2] Effective Java (Joshua Bloch, 2018) - Disponible // [#3] Clean Code (Robert C. Martin, 0) - Disponible // // Total publicaciones: 3 // Prestado: El Quijote // 'El Quijote' ya está prestado. // Devuelto: El Quijote
🐛 Errores frecuentes
Si se añade un tipo de retorno (incluso
void) a lo que se pretendía que fuera un constructor, Java lo interpreta como un método normal y no se ejecutará al crear el objeto con new.// ❌ INCORRECTO — esto es un método, NO un constructor public void Persona(String nombre) { this.nombre = nombre; } // ✅ CORRECTO — sin tipo de retorno public Persona(String nombre) { this.nombre = nombre; }
Exponer los campos directamente rompe el encapsulamiento. Si más adelante se necesita validar o transformar el dato, habrá que cambiar todo el código que accede al campo.
// ❌ INCORRECTO public String nombre; // ✅ CORRECTO private String nombre; public String getNombre() { return nombre; }
Si la clase es
public, el archivo debe llamarse exactamente igual (con la misma capitalización). public class MiClase debe estar en MiClase.java, no en miclase.java ni MI_CLASE.java.Si se añade un constructor con parámetros y se intenta crear un objeto sin argumentos (
new MiClase()), el código no compilará, porque el constructor por defecto ya no existe. Hay que declarar explícitamente el constructor sin parámetros si se desea mantener ambas opciones.📝 Ejercicios prácticos
Ejercicio 1: Comprensión — ¿Qué imprime este código?
Analiza el siguiente código y determina la salida por consola sin ejecutarlo:
public class Contador { private static int total = 0; private int id; public Contador() { total++; this.id = total; } public static void main(String[] args) { Contador a = new Contador(); Contador b = new Contador(); Contador c = new Contador(); System.out.println(a.id + " " + b.id + " " + c.id); System.out.println("Total: " + total); } }
Ejercicio 2: Aplicación — Clase Producto
Escribe una clase Producto con los siguientes requisitos:
- Campos privados:
nombre(String),precio(double),stock(int). - Constructor que valide: nombre no vacío, precio >= 0, stock >= 0.
- Método
vender(int cantidad)que disminuya el stock si hay suficiente. - Método
toString()descriptivo.
Ejercicio 3: Diseño — Clase Asignatura con constructores sobrecargados
Diseña una clase Asignatura con campos nombre (String), creditos (int) y profesor (String). Debe tener tres constructores: uno completo (los tres campos), uno parcial (nombre y créditos, con profesor = "Por asignar") y uno mínimo (solo nombre, con créditos = 6 y profesor = "Por asignar"). Usa this(...) para delegar entre constructores.
❓ Preguntas frecuentes sobre Declaración de una clase en Java
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Declaración de una clase en Java? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!