1. Campos estáticos: ¿cómo inicializarlos?
Un campo estático (static) no pertenece al objeto, sino a toda la clase. Su valor existe en una única instancia para todos los objetos de esa clase. Por analogía — es como declarar una «caja común» para todos los empleados de la empresa: no importa quién llegue, la caja es una para todos.
Inicialización en la declaración
La forma más simple y habitual de inicializar un campo estático es asignarle un valor directamente en la declaración:
public class User {
private static int userCount = 0; // inicialización aquí mismo
// ... resto del código
}
Este campo se inicializará en la primera carga de la clase User en memoria.
Inicialización en un bloque estático
A veces se necesita una lógica de inicialización más compleja — por ejemplo, cargar datos de un archivo o realizar cálculos. En ese caso se usa un bloque de inicialización estático:
public class Config {
public static String configPath;
static {
// Este bloque se ejecutará UNA vez al cargarse la clase
configPath = System.getenv("APP_CONFIG_PATH");
if (configPath == null) {
configPath = "/etc/app/default.conf";
}
System.out.println("Config path inicializado: " + configPath);
}
}
¿Cuándo se ejecuta un bloque estático?
- En el primer acceso a la clase (por ejemplo, al crear el primer objeto o al invocar cualquier método/campo estático).
- Se ejecuta solo una vez por cada clase.
Particularidades del acceso a campos estáticos
- A los campos estáticos se accede a través del nombre de la clase: User.userCount.
- También se puede acceder a través de una instancia, pero se considera mala práctica (confunde a quien lee el código).
Ejemplo:
User u1 = new User();
User u2 = new User();
System.out.println(User.userCount); // correcto
System.out.println(u1.userCount); // funciona, pero no se recomienda
2. Campos final: ¿cuándo y cómo inicializarlos?
final es un modificador que dice: «Este campo solo puede asignarse una vez y luego no cambiará». Tras la inicialización, el valor del campo se vuelve inmutable: para un objeto es una propiedad fija, y para una clase (si el campo es estático) es una constante compartida.
Ejemplos de uso:
- Constantes (por ejemplo, PI).
- Identificador único de un objeto que no debe cambiar tras su creación.
Requisitos de inicialización de los campos final
En Java hay una regla estricta: cada campo final debe inicializarse o bien en la declaración, o bien en cada constructor de la clase.
Inicialización en la declaración
public class Circle {
public static final double PI = 3.1415926535; // constante de clase
private final String id = "CIRCLE"; // constante del objeto
}
Inicialización en el constructor
A veces el valor de un campo final solo se conoce en el momento de crear el objeto:
public class User {
private final int id;
public User(int id) {
this.id = id; // asignamos el campo final en el constructor
}
}
Importante: si la clase tiene varios constructores, el campo final debe inicializarse en cada uno de ellos.
Ejemplo combinado
public class Token {
private final String value;
private final long timestamp;
public Token(String value) {
this.value = value;
this.timestamp = System.currentTimeMillis();
}
}
Errores de compilación por inicialización incorrecta
Si olvidas inicializar un campo final, el compilador no permitirá compilar el programa:
public class Broken {
private final int x; // no inicializado
public Broken() {
// x no se asigna
}
}
// Error: variable x might not have been initialized
3. Combinación de static y final: declaración de constantes de clase
Es muy habitual la combinación public static final. En Java así se declaran constantes de clase — valores que se establecen una sola vez y no cambian durante la ejecución del programa. Estas constantes pertenecen a la clase en su conjunto y son iguales para todas sus instancias.
Sintaxis y ejemplo
public class MathUtils {
public static final double PI = 3.1415926535;
public static final String APP_NAME = "MyApp";
}
Explicación:
- public — accesible desde cualquier lugar.
- static — pertenece a la clase, no a una instancia concreta.
- final — no se puede modificar después de la inicialización.
Uso
double area = MathUtils.PI * r * r;
System.out.println(MathUtils.APP_NAME);
Convención: los nombres de las constantes suelen escribirse en MAYÚSCULAS_SEPARADAS_POR_GUIONES_BAJOS.
4. Ejemplos de código: variantes de inicialización de campos estáticos y final
Ejemplo 1: Clase sencilla con una constante
public class Constants {
public static final int DAYS_IN_WEEK = 7;
public static final String COMPANY = "OOO Romashka";
}
Ejemplo 2: Campo estático inicializado en un bloque estático
public class AppConfig {
public static final String DEFAULT_PATH;
static {
// Se puede ejecutar una lógica compleja
String env = System.getenv("APP_PATH");
if (env != null) {
DEFAULT_PATH = env;
} else {
DEFAULT_PATH = "/usr/local/app";
}
}
}
Ejemplo 3: campo final de objeto, inicialización en el constructor
public class User {
private static int nextId = 1;
private final int id;
private String name;
public User(String name) {
this.id = nextId++;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Uso:
User u1 = new User("Ivan");
User u2 = new User("Maria");
System.out.println(u1.getId()); // 1
System.out.println(u2.getId()); // 2
Ejemplo 4: Error por inicialización incorrecta de un campo final
public class BadExample {
private final int number;
public BadExample() {
// number no está inicializado
}
}
// Error de compilación: variable number might not have been initialized
5. Buenas prácticas al trabajar con campos estáticos y final
Usa public static final solo para verdaderas constantes
Si el valor puede cambiar en el futuro (por ejemplo, una lista de empleados), ¡no lo declares final! Las constantes deben ser realmente inmutables.
public static final int MAX_USERS = 1000; // bien
public static final String[] USERS = new String[100]; // mal
Aunque la propia referencia USERS no cambie, el contenido del array puede modificarse. Esto puede provocar errores inesperados.
Para inicializaciones complejas, usa bloques estáticos
Si la constante no se puede expresar con una simple asignación (por ejemplo, requiere un cálculo o lectura de un archivo), utiliza un bloque estático.
No abuses de los campos estáticos
Los campos estáticos son variables globales. Un exceso de ellos puede conducir a errores difíciles de detectar y a un mantenimiento complejo del código.
No declares objetos mutables como public static final
Si un objeto es mutable, no lo hagas público ni final. Esto expone su estado interno a todos y alguien acabará aprovechándolo.
6. Errores típicos al inicializar campos estáticos y final
Error n.º 1: Campo final no inicializado. Si olvidas inicializar un campo final ya sea en la declaración o en todos los constructores, el compilador emitirá un error. Por ejemplo, si la clase tiene dos constructores y en uno de ellos olvidas asignar el campo final, habrá error.
Error n.º 2: Modificar el valor de un campo final. Intentar cambiar el valor de un campo final tras su inicialización provocará un error de compilación.
public class Demo {
private final int x = 5;
public void change() {
x = 10; // Error: cannot assign a value to final variable x
}
}
Error n.º 3: Campos static final públicos y mutables. Si declaras un objeto mutable (String[], int[], etc.) public static final, cualquier código podrá modificar su contenido. Esto rompe la encapsulación y puede llevar a errores difíciles de detectar.
Error n.º 4: Usar campos no estáticos en un bloque estático. En un bloque estático no se puede acceder a campos no estáticos porque aún no están inicializados (y de hecho no existen en ese momento).
Error n.º 5: Orden de inicialización inesperado. Si en un bloque estático accedes a campos estáticos declarados más abajo en el código, puede que aún no estén inicializados. Declara siempre los campos estáticos antes de los bloques estáticos si planeas usarlos.
GO TO FULL VERSION