Fundamentos de POO
Atributos, métodos y constructores
Aprende a definir el ciclo de vida, estado y comportamiento de los objetos en Java mediante constructores, this, miembros estáticos y sobrecarga.
Atributos, métodos y constructores
En una frase: los atributos determinan el estado de un objeto, los métodos definen sus capacidades y los constructores aseguran su correcto nacimiento; herramientas como
this,static,finaly la sobrecarga permiten afinar su comportamiento y ciclo de vida.
En la lección anterior (Clases y objetos) aprendimos qué es una clase y cómo crear instancias independientes en memoria. En esta lección profundizaremos en el diseño interno de esas clases: cómo garantizar que un objeto nunca nazca en un estado incompleto, cómo distinguir la información propia de cada instancia de la información compartida a nivel de clase, y cómo ofrecer múltiples formas de construir y operar con nuestros objetos.
¿Qué aprenderás?
Al finalizar esta lección podrás:
- Explicar la diferencia entre variables de instancia, variables locales y miembros de clase (
static). - Implementar constructores parametrizados y aprovechar la sobrecarga (overloading) de constructores y métodos.
- Comprender el ciclo de inicialización de atributos y el rol de los valores predeterminados de Java.
- Emplear la palabra clave
thispara desambiguar variables y encadenar constructores de forma limpia. - Declarar constantes de aplicación inmutables mediante la combinación
static final.
1. El problema que queremos resolver
Cuando una clase comienza a modelar un problema real, surgen necesidades esenciales de diseño:
- Objetos a medio construir: si permitimos crear un objeto sin obligar a definir sus datos vitales (por ejemplo, un producto sin precio o un boleto sin pasajero), cualquier método que intente operar con esos datos incompletos provocará cálculos erróneos o fallos en ejecución (
NullPointerException). - Diversidad al instanciar: en muchos dominios no siempre disponemos de toda la información al crear un elemento. A veces un cliente registra un producto con precio y descuento promocional; otras veces el producto no tiene descuento inicial. ¿Cómo permitimos ambas opciones sin duplicar clases ni crear métodos extraños?
- Datos duplicados innecesariamente: si vendemos 10.000 productos en un supermercado y todos aplican el mismo porcentaje de impuesto (IVA), ¿tiene sentido que cada uno de los 10.000 objetos guarde una copia idéntica de ese porcentaje en la memoria de la computadora?
- Colisión de nombres: al recibir datos en un constructor o método, lo más intuitivo es llamar al parámetro con el mismo nombre que el atributo (por ejemplo,
precio). ¿Cómo sabe Java si nos referimos al dato que viene de afuera o a la variable interna del objeto?
Resolver estas cuatro situaciones requiere dominar el uso de constructores bien definidos, la palabra clave this, la sobrecarga y los miembros static.
2. Explicación intuitiva
Para comprender estas piezas, imaginemos la fabricación de automóviles en una planta automotriz:

- El constructor es la línea de ensamblaje: nadie compra un coche que sale de fábrica sin motor ni ruedas. El constructor es el protocolo de montaje obligatorio: exige las partes indispensables para que el coche salga a la calle listo para funcionar.
- La sobrecarga de constructores son los paquetes de fábrica: puedes pedir el modelo básico (motor y color estándar) o el modelo prémium (motor, color personalizado y techo corredizo). Sigue siendo el mismo modelo de coche, pero con diferentes opciones iniciales de ensamblaje.
- La referencia
thises el pronombre “mi propio”: cuando un coche frena, no activa los frenos de los coches de los vecinos; activa sus propios frenos. Dentro del coche,thissignifica “este automóvil en el que me encuentro ahora mismo”. - Los miembros
staticson la pizarra de la fábrica: la planta tiene un panel central que indica la cantidad total de coches fabricados hoy o la velocidad máxima permitida por ley en la ciudad. Esa información no le pertenece a un solo coche en particular: es compartida y consultada por todos, existiendo a nivel de la fábrica (la clase). - El modificador
finales el número de chasis: una vez grabado al nacer el vehículo, es una constante inmutable que nadie puede alterar.
3. Definición técnica
3.1. Atributos de instancia y valores predeterminados
Los atributos de instancia son variables declaradas dentro del cuerpo de la clase pero fuera de cualquier método. Cada objeto creado a partir de la clase posee su propia copia en la memoria Heap.
En Java, si un atributo de instancia no se inicializa de forma explícita, el compilador y la máquina virtual le asignan automáticamente un valor predeterminado:
| Tipo de dato | Valor predeterminado |
|---|---|
Tipos numéricos enteros (byte, short, int, long) |
0 |
Tipos de coma flotante (float, double) |
0.0 |
Booleano (boolean) |
false |
Carácter (char) |
'\u0000' (carácter nulo) |
Referencias a objetos (String, clases personalizadas, arreglos) |
null |
Importante: las variables declaradas dentro de métodos (variables locales) no reciben valores predeterminados. El compilador de Java emitirá un error si intentas leer una variable local sin antes haberle asignado un valor.
3.2. Métodos de instancia y parámetros
Un método de instancia define una acción que puede realizar cualquier objeto de la clase. Su anatomía consta de:
- Tipo de retorno: indica el tipo de dato que el método entrega a quien lo llamó (
int,double,String, etc.). Si la operación no devuelve ningún valor, se utiliza la palabra clavevoid. - Nombre del método: por convención en Java, se escribe en formato
camelCase(por ejemplo,calcularPrecioFinal). - Lista de parámetros: variables que recibe el método entre paréntesis, separadas por comas, que actúan como datos de entrada locales para la operación.
- Cuerpo del método: bloque delimitado por llaves
{}con las instrucciones a ejecutar.
3.3. La palabra clave this
this es una referencia implícita disponible dentro de cualquier constructor o método de instancia que apunta al objeto receptor actual (la instancia sobre la cual se está ejecutando el código).
Cumple dos funciones primordiales:
- Desambiguar nombres (sombreado de variables o shadowing): cuando un parámetro tiene el mismo nombre que un atributo, el parámetro oculta al atributo dentro del bloque. Para acceder al atributo de la instancia se antepone
this.:class Producto { String nombre; Producto(String nombre) { this.nombre = nombre; // this.nombre es el atributo; nombre es el parámetro } } - Invocar constructores alternativos (
this(...)): permite que un constructor delegue parte del trabajo a otro constructor de la misma clase, reduciendo la duplicación de código. Debe ser obligatoriamente la primera sentencia del constructor.
3.4. Constructores: rol y reglas fundamentales
Un constructor es un bloque especial de código que se invoca inmediatamente después de que el operador new reserva espacio en memoria para una nueva instancia.
Reglas de oro de los constructores en Java:
- Su nombre debe coincidir exactamente con el de la clase (respetando mayúsculas y minúsculas).
- No declara ningún tipo de retorno, ni siquiera
void. Si agregasvoid, Java lo considerará un método ordinario y no un constructor. - Constructor predeterminado por omisión: si una clase no define ningún constructor explícito, el compilador de Java genera automáticamente un constructor sin parámetros que no hace nada más que inicializar atributos con sus valores predeterminados.
- Pérdida del constructor por omisión: tan pronto como escribes al menos un constructor con parámetros en tu clase, Java retira el constructor predeterminado automático. Si necesitas un constructor sin argumentos además de los parametrizados, debes escribirlo explícitamente.
3.5. Sobrecarga (Overloading)
La sobrecarga ocurre cuando dos o más métodos (o constructores) dentro de la misma clase comparten el mismo nombre pero tienen firmas de parámetros diferentes.
Para que haya sobrecarga válida, debe variar al menos uno de estos elementos:
- La cantidad de parámetros.
- Los tipos de datos de los parámetros.
- El orden de los tipos de los parámetros.
Precaución: cambiar únicamente el tipo de retorno no es suficiente para sobrecargar un método; el compilador generará un error de duplicación.
3.6. Miembros estáticos (static) y constantes (final)
- Atributos estáticos (
static): pertenecen a la clase en sí, no a una instancia particular. Existe una única copia en memoria compartida por todas las instancias de la clase. Se accede a ellos preferentemente usando el nombre de la clase:NombreClase.atributoEstatico. - Métodos estáticos (
static): operaciones que pueden ejecutarse sin necesidad de crear un objeto de la clase (comoMath.sqrt()o el propiomain).Restricción estricta: un método
staticno puede utilizarthisni acceder directamente a atributos o métodos de instancia, ya que un método estático no tiene un objeto asociado. - Constantes (
static final): la palabra clavefinalen una variable indica que su valor no puede ser reasignado una vez inicializado. Combinada constatic, define constantes globales de clase cuyos nombres se escriben por convención enMAYUSCULAS_CON_GUION_BAJO.
4. Representación visual
Observa cómo se distribuye la memoria entre los miembros propios de cada instancia (Heap) y los miembros estáticos de la clase (Metaspace / Class Area):
flowchart TD
subgraph ClaseArea["Espacio de la Clase: Producto (static)"]
IVA["Constante: IVA_GENERAL = 0.19"]
Contador["Variable estatica: totalProductos = 2"]
end
subgraph HeapMemory["Memoria Heap (Instancias individuales)"]
subgraph Obj1["Objeto 1: laptop (this)"]
A1["codigo: 101"]
A2["nombre: 'Laptop'"]
A3["precioBase: 1200.0"]
end
subgraph Obj2["Objeto 2: mouse (this)"]
B1["codigo: 102"]
B2["nombre: 'Mouse'"]
B3["precioBase: 25.0"]
end
end
Obj1 -.->|"Consulta miembro compartido"| IVA
Obj2 -.->|"Consulta miembro compartido"| IVA
Obj1 -.->|"Incrementa al crearse"| Contador
Obj2 -.->|"Incrementa al crearse"| Contador
Cómo interpretar el diagrama:
- Cada objeto (
laptopymouse) mantiene sus propios atributos (codigo,nombre,precioBase) en espacios aislados de memoria. - Los miembros estáticos (
IVA_GENERALytotalProductos) existen una sola vez a nivel de la claseProducto, evitando duplicar datos generales en cada instancia.
5. Ejemplo inicial: el problema de la inicialización manual y dispersa
Imagina un sistema de inventario donde los programadores crearon una clase sin constructores ni miembros de clase apropiados:
// Mal diseño: sin constructores adecuados ni miembros estáticos
class ProductoDefectuoso {
String codigo;
String nombre;
double precioBase;
double porcentajeIva; // ¡Cada producto duplica este valor!
}
public class EjemploProblematico {
public static void main(String[] args) {
// Se crea el objeto en blanco
ProductoDefectuoso p1 = new ProductoDefectuoso();
// Si el desarrollador olvida asignar el precio o el nombre:
System.out.println("Producto: " + p1.nombre); // Imprime: null
System.out.println("Precio base: " + p1.precioBase); // Imprime: 0.0
// Si tenemos 100 productos, debemos recordar asignar el IVA a mano en cada uno:
p1.porcentajeIva = 0.19;
// Si el IVA cambia legalmente, tendríamos que buscar y actualizar cada instancia
}
}
¿Qué problemas observamos?
- Estado inconsistente por omisión: el objeto
p1existe en memoria, pero sus atributos sonnully0.0. Nada garantiza que sea un producto válido para facturar. - Duplicación de memoria y riesgo de divergencia: si tenemos 1.000 productos y cada uno guarda su propio
porcentajeIva, un error tipográfico podría hacer que un producto aplique0.19y otro0.15. - Código cliente engorroso: quien usa la clase debe escribir 4 o 5 líneas de asignación manual tras cada
new, en lugar de inicializar todo en una sola instrucción clara.
6. Aplicación del concepto
Reescribamos la solución aplicando constructores parametrizados, encadenamiento con this(), constantes static final, contador estático y sobrecarga de métodos:
class Producto {
// 1. Constante estática de clase: compartida por todos los productos
public static final double IVA_GENERAL = 0.19;
// 2. Variable estática: cuenta cuántos productos se han creado en total
private static int totalProductosCreados = 0;
// 3. Atributos de instancia: propios de cada producto
int codigo;
String nombre;
double precioBase;
// 4. Constructor principal: recibe todos los datos indispensables
Producto(int codigo, String nombre, double precioBase) {
// Uso de 'this' para desambiguar el atributo del parámetro
this.codigo = codigo;
this.nombre = nombre;
this.precioBase = (precioBase > 0) ? precioBase : 0.0;
// Cada vez que se crea un producto, aumentamos el contador global
totalProductosCreados++;
}
// 5. Constructor sobrecargado: útil cuando aún no se conoce el precio (por defecto 0.0)
Producto(int codigo, String nombre) {
// Encadenamiento: delega en el constructor principal usando this(...)
this(codigo, nombre, 0.0);
}
// 6. Método de instancia básico: calcula el precio con IVA
double calcularPrecioFinal() {
return this.precioBase * (1.0 + IVA_GENERAL);
}
// 7. Sobrecarga de método: permite aplicar un porcentaje de descuento promocional
double calcularPrecioFinal(double porcentajeDescuento) {
if (porcentajeDescuento < 0.0 || porcentajeDescuento > 1.0) {
System.out.println("Descuento inválido. Se aplicará precio estándar.");
return calcularPrecioFinal();
}
double precioConDescuento = this.precioBase * (1.0 - porcentajeDescuento);
return precioConDescuento * (1.0 + IVA_GENERAL);
}
// 8. Método estático: consulta un dato que pertenece a la clase, no a una instancia
public static int getTotalProductosCreados() {
return totalProductosCreados;
}
void mostrarFicha() {
System.out.println("[" + this.codigo + "] " + this.nombre
+ " | Base: $" + this.precioBase
+ " | Final (c/IVA): $" + calcularPrecioFinal());
}
}
public class GestionInventario {
public static void main(String[] args) {
System.out.println("Productos antes de iniciar: " + Producto.getTotalProductosCreados());
// Usamos el constructor principal
Producto laptop = new Producto(101, "Laptop Profesional", 1200.0);
// Usamos el constructor sobrecargado
Producto teclado = new Producto(102, "Teclado Mecánico");
// Mostramos las fichas iniciales
laptop.mostrarFicha();
teclado.mostrarFicha();
// Probamos la sobrecarga de métodos
double precioConPromo = laptop.calcularPrecioFinal(0.10); // 10% de descuento
System.out.println("Laptop con 10% descuento: $" + precioConPromo);
// Consultamos el contador estático mediante la clase
System.out.println("Total de productos creados: " + Producto.getTotalProductosCreados());
}
}
Explicación del código
this.codigo = codigo: aclara a Java que el valor del parámetrocodigodebe asignarse a la variable de instanciacodigodel objeto que se está creando.this(codigo, nombre, 0.0): el segundo constructor no duplica la lógica de asignación ni el incremento del contador; delega la tarea al constructor principal garantizando consistencia.calcularPrecioFinal()vscalcularPrecioFinal(double): son dos métodos con el mismo nombre pero diferente lista de argumentos (sobrecarga). El compilador sabe exactamente cuál ejecutar según los parámetros pasados en la llamada.Producto.IVA_GENERALyProducto.getTotalProductosCreados(): se invocan directamente sobre la claseProducto. No requieren que exista ningún objeto para ser referenciados.
Cómo ejecutar el ejemplo
- Guarda el código en un archivo llamado
GestionInventario.java. - Compila en la terminal con:
javac GestionInventario.java - Ejecuta el programa con:
java GestionInventario
Resultado esperado:
Productos antes de iniciar: 0
[101] Laptop Profesional | Base: $1200.0 | Final (c/IVA): $1428.0
[102] Teclado Mecánico | Base: $0.0 | Final (c/IVA): $0.0
Laptop con 10% descuento: $1285.2
Total de productos creados: 2
7. Comparación entre enfoques
| Aspecto | Miembros de instancia | Miembros de clase (static) |
|---|---|---|
| Pertenencia | Pertenecen a un objeto individual específico. | Pertenecen a la clase en su totalidad. |
| Espacio en memoria | Una copia independiente por cada objeto creado (Heap). |
Una única copia compartida para todo el programa. |
Acceso a this |
Sí tiene acceso al objeto actual mediante this. |
No tiene acceso a this ni a variables de instancia. |
| Forma de invocación recomendada | Mediante la referencia del objeto: laptop.mostrarFicha(). |
Mediante el nombre de la clase: Producto.getTotalProductosCreados(). |
| Propósito típico | Modelar el estado y las acciones individuales de cada entidad. | Constantes compartidas, utilidades matemáticas o contadores globales. |
8. ¿Cuándo utilizar este concepto?
Casos en los que resulta indispensable
- Constructores obligatorios: siempre que una entidad requiera ciertos datos mínimos para tener sentido en el dominio (por ejemplo, una cuenta no puede existir sin número de identificación).
- Sobrecarga de constructores (
this(...)): cuando sea habitual crear objetos con configuraciones por defecto o datos parciales sin obligar al usuario a suministrar todos los parámetros. static final: para valores constantes que rigen a todo el dominio y no cambian durante la ejecución (códigos de error, porcentajes fiscales, factores de conversión física).- Sobrecarga de métodos: cuando una misma operación lógica puede realizarse con distintos tipos o volúmenes de información de entrada (por ejemplo, buscar un usuario por
idnumérico o porcorreoelectrónico).
Cuándo no utilizarlo o tener precaución
- Abuso de
static(el antipatrón del “estado global”): no utilices variablesstaticpara guardar información que debería pertenecer a un usuario o sesión particular. Las variables estáticas mutables dificultan las pruebas unitarias y causan errores graves en aplicaciones concurrentes. - Sobrecarga excesiva o confusa: si sobrecargas un método con tipos fácilmente convertibles entre sí (como
intyshort, o múltiples combinaciones booleanas), el código se vuelve ambiguo y difícil de leer. En esos casos es preferible utilizar nombres de métodos distintos y descriptivos.
9. Errores frecuentes
Error 1: Intentar usar this o atributos de instancia dentro de un contexto static
Qué sucede:
class Demo {
int valor = 10;
public static void imprimir() {
System.out.println(this.valor); // Error de compilación: non-static variable cannot be referenced from a static context
}
}
Por qué ocurre: un método estático pertenece a la clase y puede ejecutarse sin que exista ningún objeto instanciado. Por lo tanto, no hay ningún objeto al que this pueda apuntar.
Cómo evitarlo: si necesitas acceder a atributos de instancia, el método debe ser de instancia (elimina la palabra clave static). Si el método debe ser estático, debe recibir el objeto como parámetro explícito.
Error 2: Asumir que el constructor por defecto sigue existiendo tras crear uno propio
Qué sucede:
class Usuario {
String nombre;
Usuario(String nombre) {
this.nombre = nombre;
}
}
// En otra parte:
Usuario u = new Usuario(); // Error: constructor Usuario in class Usuario cannot be applied to given types
Por qué ocurre: tan pronto como defines un constructor personalizado, el compilador retira el constructor por defecto sin argumentos.
Cómo evitarlo: si necesitas permitir la creación de objetos sin parámetros, escribe explícitamente el constructor vacío: Usuario() { }.
Error 3: Colocar la llamada this(...) después de otras sentencias en el constructor
Qué sucede:
class Libro {
String titulo;
int paginas;
Libro(String titulo) {
System.out.println("Creando libro...");
this(titulo, 100); // Error: call to this must be first statement in constructor
}
Libro(String titulo, int paginas) {
this.titulo = titulo;
this.paginas = paginas;
}
}
Por qué ocurre: Java exige que la inicialización del objeto delegada en otro constructor se complete antes de que se ejecute cualquier instrucción adicional.
Cómo evitarlo: coloca siempre this(...) como la primera línea dentro del cuerpo del constructor.
10. Ejercicio práctico
Enunciado
Diseña una clase llamada BoletoVuelo que gestione la venta de pasajes aéreos bajo las siguientes especificaciones:
Requisitos:
- Atributos de instancia:
codigoVuelo(String).nombrePasajero(String).precioBase(double).esClaseEjecutiva(boolean).
- Miembros de clase (
static):- Una constante pública
TASA_AEROPORTUARIAde valor fijo35.0(dólares). - Una variable privada
totalBoletosEmitidosque cuente cuántos boletos se han creado en total. - Un método público estático
getTotalBoletosEmitidos()que devuelva dicho conteo.
- Una constante pública
- Constructores:
- Un constructor completo que reciba los 4 datos y verifique que
precioBaseno sea negativo. Debe incrementartotalBoletosEmitidos. - Un constructor sobrecargado que reciba únicamente
codigoVuelo,nombrePasajeroyprecioBase, delegando en el constructor principal mediantethis(...)conesClaseEjecutivaenfalse.
- Un constructor completo que reciba los 4 datos y verifique que
- Métodos:
calcularPrecioTotal(): devuelve el precio final sumando el precio base, laTASA_AEROPORTUARIA, y un recargo del 30% sobre el precio base si el boleto es de clase ejecutiva.- Sobrecarga
calcularPrecioTotal(double porcentajeDescuento): aplica primero el descuento al precio base antes de sumar la tasa aeroportuaria y el recargo. imprimirBoleto(): imprime en pantalla un resumen con los datos del boleto y su precio total.
Pistas
Mostrar pistas
- Declara la constante como
public static final double TASA_AEROPORTUARIA = 35.0;. - En el constructor sobrecargado de 3 parámetros, la primera línea debe ser
this(codigoVuelo, nombrePasajero, precioBase, false);. - Para el recargo de clase ejecutiva, puedes calcular:
double recargo = esClaseEjecutiva ? (baseCalculo * 0.30) : 0.0;. - Recuerda incrementar
totalBoletosEmitidos++en el constructor principal.
Solución propuesta
Mostrar solución y explicación
class BoletoVuelo {
// Constante compartida
public static final double TASA_AEROPORTUARIA = 35.0;
// Contador de clase
private static int totalBoletosEmitidos = 0;
// Atributos de instancia
String codigoVuelo;
String nombrePasajero;
double precioBase;
boolean esClaseEjecutiva;
// Constructor completo
BoletoVuelo(String codigoVuelo, String nombrePasajero, double precioBase, boolean esClaseEjecutiva) {
this.codigoVuelo = codigoVuelo;
this.nombrePasajero = nombrePasajero;
this.precioBase = (precioBase >= 0.0) ? precioBase : 0.0;
this.esClaseEjecutiva = esClaseEjecutiva;
totalBoletosEmitidos++;
}
// Constructor sobrecargado (económica por defecto)
BoletoVuelo(String codigoVuelo, String nombrePasajero, double precioBase) {
this(codigoVuelo, nombrePasajero, precioBase, false);
}
// Método de cálculo estándar
double calcularPrecioTotal() {
double recargo = this.esClaseEjecutiva ? (this.precioBase * 0.30) : 0.0;
return this.precioBase + recargo + TASA_AEROPORTUARIA;
}
// Método sobrecargado con descuento promocional
double calcularPrecioTotal(double porcentajeDescuento) {
if (porcentajeDescuento <= 0.0 || porcentajeDescuento >= 1.0) {
return calcularPrecioTotal();
}
double baseConDescuento = this.precioBase * (1.0 - porcentajeDescuento);
double recargo = this.esClaseEjecutiva ? (baseConDescuento * 0.30) : 0.0;
return baseConDescuento + recargo + TASA_AEROPORTUARIA;
}
public static int getTotalBoletosEmitidos() {
return totalBoletosEmitidos;
}
void imprimirBoleto() {
System.out.println("BOLETO: " + this.codigoVuelo
+ " | Pasajero: " + this.nombrePasajero
+ " | Clase: " + (this.esClaseEjecutiva ? "Ejecutiva" : "Económica")
+ " | Total a pagar: $" + calcularPrecioTotal());
}
}
public class SistemaVuelos {
public static void main(String[] args) {
System.out.println("Boletos emitidos al abrir sistema: " + BoletoVuelo.getTotalBoletosEmitidos());
// Boleto en clase económica usando constructor secundario
BoletoVuelo boleto1 = new BoletoVuelo("AV120", "Martín Gómez", 200.0);
// Boleto en clase ejecutiva usando constructor principal
BoletoVuelo boleto2 = new BoletoVuelo("IB601", "Lucía Peña", 500.0, true);
boleto1.imprimirBoleto();
boleto2.imprimirBoleto();
// Aplicamos descuento al boleto ejecutivo
double precioConDescuento = boleto2.calcularPrecioTotal(0.15); // 15% de descuento
System.out.println("Precio de Lucía con 15% desc: $" + precioConDescuento);
System.out.println("Total final de boletos emitidos: " + BoletoVuelo.getTotalBoletosEmitidos());
}
}
Resultado esperado:
Boletos emitidos al abrir sistema: 0
BOLETO: AV120 | Pasajero: Martín Gómez | Clase: Económica | Total a pagar: $235.0
BOLETO: IB601 | Pasajero: Lucía Peña | Clase: Ejecutiva | Total a pagar: $685.0
Precio de Lucía con 15% desc: $587.5
Total final de boletos emitidos: 2
Explicación:
El constructor de tres argumentos delega en el de cuatro utilizando this(...), asegurando que totalBoletosEmitidos se incremente exactamente una vez por objeto creado. La constante TASA_AEROPORTUARIA no se multiplica en memoria por cada boleto, y el método sobrecargado calcularPrecioTotal reutiliza la misma fórmula financiera con y sin descuento.
11. Resumen de la lección
- Ciclo de vida: los constructores garantizan que un objeto inicie su existencia con los datos necesarios, evitando estados incompletos.
- Referencia
this: apunta al objeto receptor actual, permite resolver colisiones entre parámetros y atributos, y permite invocar otros constructores conthis(...). - Sobrecarga: permite definir múltiples versiones de métodos o constructores con el mismo nombre y diferente lista de parámetros, aumentando la flexibilidad de la clase.
- Miembros estáticos (
static): pertenecen a la clase y no a un objeto individual. Se emplean para constantes globales (static final), métodos utilitarios y valores compartidos. - Inmutabilidad con
final: previene la reasignación de variables y atributos una vez inicializados.
12. Comprueba tu comprensión
- Si una clase define un constructor
Usuario(String nombre), ¿por qué la líneaUsuario u = new Usuario();causará un error de compilación? - ¿Por qué no es posible utilizar la referencia
thisdentro del cuerpo de un método declarado comopublic static void main(String[] args)? - ¿Cuál es la diferencia entre el ámbito de vida en memoria de una variable declarada dentro de un método y un atributo de instancia?
- Si dos métodos tienen el mismo nombre y la misma lista de parámetros pero devuelven tipos distintos (uno
inty otrodouble), ¿es una sobrecarga válida en Java? Justifica tu respuesta.
13. Continúa aprendiendo
- Lección anterior: Clases y objetos
- Siguiente lección recomendada: Encapsulamiento — donde aprenderás a proteger los atributos de tus objetos mediante modificadores de acceso (
private,public) y métodos getters y setters. - Ruta de aprendizaje: Fundamentos de POO
14. Fuentes y lecturas recomendadas
- Oracle. The Java Tutorials: Classes and Objects — Defining Classes, Providing Constructors, Passing Information to a Method. docs.oracle.com/javase/tutorial/java/javaOO/
- Cay S. Horstmann. Core Java Volume I: Fundamentals (12th Edition). Pearson, 2022. Capítulo 4: «Objects and Classes».
- James Gosling, Bill Joy, Guy Steele, Gilad Bracha, Alex Buckley, Daniel Smith, Gavin Bierman. The Java Language Specification (Java SE 21 Edition). Oracle, 2023. Sección 8.8: «Constructor Declarations».