static în Java

static leagă un câmp sau o metodă de clasă, nu de un obiect: există o singură copie, accesată prin numele clasei.

Sintaxă
class Contor {
    static int total;               // un singur câmp, comun tuturor obiectelor
    static int urmatorul() {        // se apelează pe clasă: Contor.urmatorul()
        return ++total;
    }
    static { /* bloc de inițializare, rulează o dată */ }
}

Ce face static

Un câmp obișnuit există în fiecare obiect. Un câmp static există o singură dată pentru toată clasa și este împărțit de toate obiectele. Îl accesezi prin numele clasei: Contor.total. Este potrivit pentru contoare, cache-uri și constante (static final).

O metodă static se apelează fără obiect: Math.max(3, 7), Integer.parseInt("42"). Pentru că nu are obiect, nu are this și nu poate folosi direct câmpurile sau metodele nestatice. De aceea main este static: JVM-ul îl poate apela fără să construiască un obiect.

Un bloc static { ... } rulează o singură dată, când clasa este încărcată, înainte de prima ei folosire. O clasă internă static nu are legătură cu un obiect al clasei exterioare. Importul static (import static java.lang.Math.*;) permite apelul fără numele clasei.

Exemple

Exemplul 1: Câmp static comun și câmp de obiect

Fiecare bon primește un număr diferit (câmpul obiectului), luat din contorul comun urmatorulNumar (câmpul static).

class Bon {
    static int urmatorulNumar = 1;
    static double totalZi = 0;

    final int numar;
    final double suma;

    Bon(double suma) {
        this.numar = urmatorulNumar++;
        this.suma = suma;
        totalZi += suma;
    }
}

public class Main {
    public static void main(String[] args) {
        Bon b1 = new Bon(45.50);
        Bon b2 = new Bon(12.00);
        Bon b3 = new Bon(130.25);
        System.out.println("bonuri: " + b1.numar + ", " + b2.numar + ", " + b3.numar);
        System.out.println("următorul număr: " + Bon.urmatorulNumar);
        System.out.println("total zi: " + Bon.totalZi + " lei");
    }
}

Rezultat

bonuri: 1, 2, 3
următorul număr: 4
total zi: 187.75 lei

Exemplul 2: Metode static ajutătoare și blocul static

Clasa Conversii are doar metode statice și un constructor privat, ca nimeni să nu creeze obiecte. Blocul static rulează o singură dată, la prima folosire a clasei.

import java.util.HashMap;
import java.util.Map;

final class Conversii {
    private static final Map<String, Double> CURSURI = new HashMap<>();

    static {
        System.out.println("(se încarcă cursurile)");
        CURSURI.put("EUR", 5.08);
        CURSURI.put("USD", 4.37);
    }

    private Conversii() {
    }

    static double inLei(double suma, String moneda) {
        return suma * CURSURI.getOrDefault(moneda, 1.0);
    }

    static double celsiusInFahrenheit(double c) {
        return c * 9 / 5 + 32;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("pornire");
        System.out.printf("100 EUR = %.2f lei%n", Conversii.inLei(100, "EUR"));
        System.out.printf("20 USD = %.2f lei%n", Conversii.inLei(20, "USD"));
        System.out.println("25 °C = " + Conversii.celsiusInFahrenheit(25) + " °F");
    }
}

Rezultat

pornire
(se încarcă cursurile)
100 EUR = 508.00 lei
20 USD = 87.40 lei
25 °C = 77.0 °F

Exemplul 3: Din main nu vezi direct câmpurile nestatice

main este static, deci poate apela direct doar alți membri statici. Pentru metoda nestatică saluta trebuie un obiect.

public class Main {
    static int vizite = 0;
    String limba = "ro";

    static void inregistreaza() {
        vizite++;
    }

    String saluta(String nume) {
        return limba.equals("ro") ? "Bună, " + nume + "!" : "Hello, " + nume + "!";
    }

    public static void main(String[] args) {
        inregistreaza();
        inregistreaza();
        System.out.println("vizite: " + vizite);

        // System.out.println(saluta("Ana"));  // eroare: non-static method cannot be referenced from a static context
        Main aplicatie = new Main();
        System.out.println(aplicatie.saluta("Ana"));
    }
}

Rezultat

vizite: 2
Bună, Ana!

Greșeli frecvente

  • Apelezi o metodă nestatică din main: non-static method saluta(String) cannot be referenced from a static context. Creează un obiect sau fă metoda static, dacă nu folosește câmpurile obiectului.
  • Faci un câmp static din greșeală: toate obiectele ajung să împartă aceeași valoare (de exemplu toți elevii au același nume).
  • Accesezi membrii statici printr-un obiect (b1.totalZi). Compilează, dar induce în eroare și -Xlint avertizează (static variable should be qualified by type name). Scrie Bon.totalZi.

Comenzi înrudite

  • final (și static final): final interzice schimbarea: o variabilă primește valoare o singură dată, o metodă nu poate fi rescrisă, o clasă nu poate fi extinsă.
  • main și structura unui program: Orice program Java pornește din metoda main a unei clase: public static void main(String[] args).
  • Metode: O metodă grupează cod sub un nume, primește parametri și poate returna o valoare; Java permite supraîncărcare și varargs.
  • Clase interne și anonime: O clasă poate fi declarată în altă clasă (statică sau interioară), într-o metodă (locală) sau direct la folosire, fără nume (anonimă).
  • Pachete și importuri (package, import): package așază clasa într-un pachet (un spațiu de nume, ca un director); import permite folosirea claselor din alte pachete după numele scurt.