W3docs

Palabra clave static en Java

Declara miembros a nivel de clase en Java con static — campos estáticos, métodos, bloques y clases anidadas estáticas.

static es la palabra clave que promueve un miembro de clase de "uno por instancia" a "uno por clase." Un campo estático tiene una única copia compartida por todos los objetos. Un método estático pertenece a la clase misma y se ejecuta sin ninguna instancia. Un bloque estático se ejecuta una vez, cuando la clase se carga por primera vez. Una clase anidada estática vive dentro de otra clase sin necesitar un objeto envolvente.

La regla de oro única: los miembros static no tienen this. Todo lo demás sobre cómo se comportan se deriva de eso.

Campos estáticos

Un campo estático se declara con static en el cuerpo de la clase. Existe exactamente una copia, independientemente de cuántas instancias existan:

public class Counter {
  static int total;       // one Counter.total for everybody
  int count;              // each Counter has its own count
}

Counter a = new Counter();   a.count++;   Counter.total++;
Counter b = new Counter();   b.count++;   Counter.total++;

System.out.println(a.count);          // 1
System.out.println(b.count);          // 1
System.out.println(Counter.total);    // 2

Se accede a un campo estático a través del nombre de la clase (Counter.total) — esa es la forma canónica. Java también permite escribir a.total porque a es un Counter, pero cualquier linter del mundo marca ese estilo.

Métodos estáticos

Un método estático pertenece a la clase. Se invoca con ClassName.method(...):

public class MathUtil {
  public static int square(int n) {
    return n * n;
  }
}

int x = MathUtil.square(7);     // 49

Dentro de un método estático no existe this — no se pueden leer campos de instancia ni llamar a métodos de instancia sin calificar, porque no hay ninguna instancia actual desde la que leerlos:

public class Counter {
  int count;
  static void reset() {
    count = 0;      // ERROR: cannot reference instance field from static context
  }
}

Aún puedes recibir una instancia como parámetro y operar sobre ella:

static void resetThis(Counter c) {
  c.count = 0;     // ok — c is a parameter, not this
}

La dirección inversa funciona bien: un método de instancia puede llamar a un método estático sin ningún protocolo especial, porque la clase siempre está disponible incluso cuando existe una instancia.

Cuándo elegir static

La única prueba es si el miembro depende del estado por instancia.

¿Depende de this?Usa
No — cálculo puro, contador compartido, método de fábricastatic
Sí — lee o escribe los campos propios del objetoinstancia
public static int hoursToSeconds(int h) { return h * 3600; }   // no this needed → static
public        int rentalDays()           { return days; }       // reads this.days → instance

Un problema común: un método de instancia que ignora this. Está mintiendo sobre ser específico de instancia — conviértelo en static y el llamador ya no necesita inventar un objeto solo para usarlo.

Constantes estáticas

La combinación static final es la forma estándar para constantes:

public static final double TAX_RATE = 0.08;
public static final int    MAX_RETRIES = 3;
public static final String DEFAULT_LOCALE = "en";

Por convención, las constantes se nombran en UPPER_SNAKE_CASE. Se insertan en tiempo de compilación cuando el valor es primitivo o un literal String, lo que las hace tan rápidas como un literal en el punto de llamada.

Bloques estáticos

Un bloque static { ... } se ejecuta una vez, cuando la clase se carga por primera vez en la JVM. Úsalo para la configuración única de campos estáticos que necesitan más que una sola expresión:

public class Lookup {
  static final Map<String, Integer> WEEKDAYS = new HashMap<>();
  static {
    WEEKDAYS.put("Mon", 1);
    WEEKDAYS.put("Tue", 2);
    WEEKDAYS.put("Wed", 3);
    WEEKDAYS.put("Thu", 4);
    WEEKDAYS.put("Fri", 5);
    WEEKDAYS.put("Sat", 6);
    WEEKDAYS.put("Sun", 7);
  }
}

Los bloques estáticos son potentes pero fáciles de usar en exceso. Prefiere un inicializador de campo simple cuando una expresión es suficiente.

Los campos estáticos y los bloques estáticos se ejecutan de arriba a abajo en el orden en que aparecen en el código fuente. Si un inicializador accede a un campo (a través de un método) antes de que se haya ejecutado la línea propia de ese campo, verá el valor predeterminado (0, false o null) — por lo tanto, el orden importa:

public class Order {
  static int a = compute();          // runs first; b is still 0 → a becomes 1
  static int b = 10;                 // runs second
  static int compute() { return b + 1; }
}
// Order.a == 1, Order.b == 10

(Leer b directamente en esa primera línea — static int a = b + 1; — es en cambio un error de compilación "illegal forward reference"; solo la ruta indirecta a través de un método expone el valor predeterminado.)

Clases anidadas estáticas

Una clase declarada static dentro de otra clase es una clase anidada estática. A diferencia de una clase interna no estática, no lleva una referencia implícita a una instancia de la clase externa:

public class Outer {
  static class Inner {           // does not need an Outer instance
    void hello() { System.out.println("hi"); }
  }
}

Outer.Inner i = new Outer.Inner();   // create directly
i.hello();

Así es como hemos estado envolviendo clases auxiliares en el mismo archivo que main en bloques anteriores static class Foo {...}main es estático, por lo que necesitamos que el auxiliar también sea estático para instanciarlo sin una instancia envolvente Outer. El capítulo de clases anidadas cubre los cuatro tipos.

static no es "el constructor"

Los principiantes a veces confunden "static = se ejecuta una vez" con "static = se ejecuta al crear el objeto." La inicialización estática ocurre una vez por clase, no una vez por objeto. El constructor se ejecuta una vez por objeto. Son mecanismos distintos y se activan en situaciones diferentes.

Miembros estáticos en interfaces

Las interfaces también pueden tener métodos static. Se comportan igual que los estáticos de clase — se invocan con InterfaceName.method(...):

public interface Path {
  static Path of(String s) { return new SimplePath(s); }
}

Path p = Path.of("/tmp/foo");

El capítulo de interfaces cubre cuándo es buena idea hacerlo (métodos de fábrica en la propia interfaz).

Un ejemplo completo

java— editable, runs on the server

Este programa imprime:

#1  apple   base=0.50 USD,  with tax=0.54
#2  bread   base=2.40 USD,  with tax=2.59
#3  butter  base=3.10 USD,  with tax=3.35
Total items ever created: 3

Observa cómo el ejemplo combina los cuatro tipos: las constantes y la tabla de búsqueda se rellenan antes de que exista cualquier Item, cada Item conserva su propio name y basePrice, y el único campo compartido itemsCreated proporciona el id incremental.

Qué sigue

static permite indicar quién es propietario de un miembro. El siguiente complemento es final, que permite indicar si puede cambiar. Juntos, static final es la forma estándar para constantes; por sí solo, final da forma a la herencia y al diseño inmutable. Continúa en java-final.

Práctica

Práctica
¿Por qué un método estático produce un error de compilación si intenta leer un campo de instancia por su nombre simple?
¿Por qué un método estático produce un error de compilación si intenta leer un campo de instancia por su nombre simple?
Was this page helpful?