Java: quando è utile un blocco di inizializzazione statico?


96

Qual è la differenza tra l'inizializzazione all'interno di un staticblocco:

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

E inizializzazione statica individuale:

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....

1
Stai usando solo assegnazioni nel blocco di inizializzazione statica, quindi ovviamente quelle potrebbero essere fatte usando l'assegnazione di variabili statiche. Hai provato a vedere cosa succede se hai bisogno di eseguire dichiarazioni di non assegnazione?
Platinum Azure

È un buon posto per caricare le classi o caricare la libreria nativa.
qrtt1

1
Si noti che le variabili statiche dovrebbero essere evitate e quindi i blocchi di inizializzazione statici generalmente non sono una grande idea. Se ti accorgi di usarli molto, aspettati qualche problema su tutta la linea.
Bill K

Risposte:


113

Un blocco di inizializzazione statico consente un'inizializzazione più complessa, ad esempio utilizzando condizionali:

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

O quando è richiesta più della semplice costruzione: quando si utilizza un builder per creare la propria istanza, è necessaria la gestione delle eccezioni o un lavoro diverso dalla creazione di campi statici.

Un blocco di inizializzazione statico viene eseguito anche dopo gli inizializzatori statici inline, quindi è valido quanto segue:

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}

3
Facendo "b = a * 4;" inline sarebbe un problema solo se b fosse dichiarato prima di a, il che non è il caso nel tuo esempio.
George Hawkins

1
@GeorgeHawkins Stavo solo cercando di illustrare che un inizializzatore statico viene eseguito dopo gli inizializzatori in linea, non che non si possa fare un equivalente in linea. Tuttavia, prendo il tuo punto e ho aggiornato l'esempio per (si spera) essere più chiaro.
Rich O'Kelly

1
Solo per divertimento potrei sottolineare che il tuo primo esempio potrebbe essere altrettanto facilmente "static double a = someCondition? 0: 1;" Non che i tuoi esempi non siano eccezionali, sto solo dicendo ... :)
Bill K

18

Un utilizzo tipico:

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

Come lo faresti senza un inizializzatore statico?


2
Risposta: Guava :) +1
Paul Bellora

2
Un'altra risposta senza librerie aggiuntive: creare un metodo statico che incapsuli l'inizializzazione SETe utilizzare la variabile initializer ( private final static Set<String> SET = createValueSet()). E se avessi 5 set e 2 mappe, scaricheresti tutti in un unico staticblocco?
TWiStErRob

16

Puoi usare il blocco try / catch all'interno static{}come di seguito:

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

PS: Riferito da questo !


12

La gestione delle eccezioni durante l'inizializzazione è un altro motivo. Per esempio:

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

Ciò è utile per i costruttori che generano fastidiosamente eccezioni controllate, come sopra, oppure logica di inizializzazione più complessa che potrebbe essere soggetta a eccezioni.


5

A volte si desidera fare di più che assegnare valori alle variabili statiche. Poiché non è possibile inserire istruzioni arbitrarie nel corpo della classe, è possibile utilizzare un blocco inizializzatore statico.


4

Nel tuo esempio, non c'è differenza; ma spesso il valore iniziale è più complesso di quanto sia comodamente espresso in una singola espressione (ad esempio, è un i List<String>cui contenuti sono espressi al meglio da un for-loop; o è un Methodche potrebbe non esistere, quindi sono necessari gestori di eccezioni), e / o i campi statici devono essere impostati in un ordine specifico.


4

staticblock può essere utilizzato per inizializzare l' istanza singleton , per impedire l'utilizzo del metodo sincronizzato getInstance() .


3

Tecnicamente, potresti farcela senza di essa. Alcuni preferiscono che il codice di inizializzazione multilinea entri in un metodo statico. Sono abbastanza contento di utilizzare un inizializzatore statico per un'inizializzazione multistate relativamente semplice.

Ovviamente, creerei quasi sempre la mia statistica finale indicherei un oggetto non modificabile.


3

La parola chiave statica (sia che si tratti di una variabile o di un blocco) appartiene alla classe. Quindi, quando viene chiamata la classe, queste variabili o blocchi vengono eseguiti. Quindi la maggior parte dell'inizializzazione verrà eseguita con l'aiuto della parola chiave statica. Poiché appartiene alla classe stessa, la classe può accedervi direttamente, senza creare un'istanza della classe.

Facciamo un esempio, c'è una classe di scarpe in cui ci sono diverse variabili come colore, taglia, marca, ecc ... E qui se l'azienda produttrice di scarpe ha un solo marchio, dovremmo inizializzarlo come variabile statica. Quindi, quando viene chiamata la classe di scarpe e vengono prodotti diversi tipi di scarpe (creando un'istanza della classe) in quel momento il colore e le dimensioni occuperanno la memoria ogni volta che viene creata una nuova scarpa, ma qui il marchio è una proprietà comune per tutte le scarpe, in modo che occupi la memoria per una volta, indipendentemente dal numero di scarpe prodotte.

Esempio:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}

1

Il blocco di codice statico consente di inizializzare i campi con più di un'istruzione, inizializza i campi in un ordine diverso delle dichiarazioni e potrebbe anche essere utilizzato per l'inizializzazione condizionale.

Più specificamente,

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

non funzionerà perché aeb sono dichiarati dopo ab.

Tuttavia potrei usare un init statico. blocco per superare questo.

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}

3
Anche se quello che stai dicendo è vero, non dimostra la necessità di un blocco di inizializzazione statico. Puoi semplicemente spostare la tua abdichiarazione sotto la dichiarazione di b.
gawi

1

Usiamo i costruttori per inizializzare le nostre variabili di istanza (variabili non statiche, variabili che appartengono a oggetti, non alla classe).

Se vuoi inizializzare le variabili di classe (variabili statiche) e vuoi farlo senza creare un oggetto (i costruttori possono essere chiamati solo durante la creazione di un oggetto), allora hai bisogno di blocchi statici.

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}

Leggere stdin in un inizializzatore statico è un'idea piuttosto orribile. Ed System.out.println("B * H");è abbastanza inutile. E la risposta stessa è piuttosto vaga. OP non ha menzionato costruttori o variabili di istanza.
shmosel

Questo è solo un esempio che mostra cos'è un inizializzatore statico e come viene utilizzato. OP non ha chiesto costruttori o variabili di istanza ma per insegnargli la differenza dell'inizializzatore statico dal costruttore deve saperlo. Altrimenti direbbe "Perché non uso solo un costruttore per inizializzare le mie variabili statiche?"
Michael

0

Un blocco di inizializzazione statico è utile se si desidera inizializzare i tipi statici della classe specificati, prima del primo utilizzo della classe. L'utilizzo successivo non richiamerà alcun blocco di inizializzazione statica. È l'esatto opposto degli inizializzatori di istanza, che inizializzano i membri dell'istanza.


0

Quando vuoi valutare una certa espressione durante il tempo di caricamento della classe, puoi utilizzare il blocco statico ma ricorda:

È necessario gestire un'eccezione in un blocco statico, il che significa che non è possibile generare un'eccezione da un blocco statico.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.