Quando vengono inizializzate le variabili statiche?


88

Mi chiedo quando le variabili statiche vengono inizializzate ai valori predefiniti. È corretto che quando una classe viene caricata, vengono create (allocate) variabili statiche, quindi vengono eseguiti gli inizializzatori statici e le inizializzazioni nelle dichiarazioni? A che punto vengono forniti i valori di default? Questo porta al problema del riferimento in avanti.

Inoltre, se puoi spiegare questo in riferimento alla domanda posta su Perché i campi statici non vengono inizializzati in tempo? e soprattutto la risposta data da Kevin Brock sullo stesso sito. Non riesco a capire il terzo punto.


2
Si prega di modificare la domanda per includere la citazione a cui si fa riferimento.
Oliver Charlesworth

1
Hai letto le specifiche del linguaggio Java? È un documento abbastanza leggibile, deliberatamente. Se l'hai letto, potresti capire cosa sta succedendo. In caso contrario, puoi fare almeno una domanda più specifica ...
Maarten Bodewes

Penso che questa domanda e risposta sia un duplice di stackoverflow.com/questions/3499214 .
Stephen C

Risposte:


72

Da Vedere Metodi variabili statiche Java :

  • È una variabile che appartiene alla classe e non all'oggetto (istanza)
  • Le variabili statiche vengono inizializzate una sola volta, all'inizio dell'esecuzione. Queste variabili verranno inizializzate per prime, prima dell'inizializzazione di qualsiasi variabile di istanza
  • Una singola copia da condividere da tutte le istanze della classe
  • È possibile accedere a una variabile statica direttamente dal nome della classe e non necessita di alcun oggetto.

Le variabili di istanza e di classe (statiche) vengono inizializzate automaticamente ai valori predefiniti standard se non vengono inizializzate di proposito. Sebbene le variabili locali non vengano inizializzate automaticamente, non è possibile compilare un programma che non riesce a inizializzare una variabile locale o ad assegnare un valore a quella variabile locale prima che venga utilizzata.

Ciò che il compilatore effettivamente fa è produrre internamente una singola routine di inizializzazione della classe che combina tutti gli inizializzatori di variabili statiche e tutti i blocchi di codice degli inizializzatori statici, nell'ordine in cui appaiono nella dichiarazione della classe. Questa singola procedura di inizializzazione viene eseguita automaticamente, una sola volta, al primo caricamento della classe.

In caso di classi interne , non possono avere campi statici

Una classe interna è una classe nidificata che non è dichiarata esplicitamente o implicitamente static.

...

Le classi interne non possono dichiarare inizializzatori statici (§8.7) o interfacce membro ...

Le classi interne non possono dichiarare membri statici, a meno che non siano variabili costanti ...

Vedere JLS 8.1.3 Classi interne e istanze di contenimento

finali campi in Java possono essere inizializzati separatamente dalla loro posizione di dichiarazione, ma non può essere applicabile ai static finalcampi. Vedi l'esempio sotto.

final class Demo
{
    private final int x;
    private static final int z;  //must be initialized here.

    static 
    {
        z = 10;  //It can be initialized here.
    }

    public Demo(int x)
    {
        this.x=x;  //This is possible.
        //z=15; compiler-error - can not assign a value to a final variable z
    }
}

Questo perché c'è solo una copia delle staticvariabili associate al tipo, piuttosto che una associata a ciascuna istanza del tipo come con le variabili di istanza e se proviamo a inizializzare il ztipo static finalall'interno del costruttore, tenterà di reinizializzare il static finalcampo del tipo zperché il costruttore viene eseguito su ogni istanza della classe che non deve ricorrere ai finalcampi statici .


5
In case of static inner classes, they can not have static fieldssembra un errore di battitura. Le classi interne non sono statiche.
Daniel Lubarov

Dovresti usare comunque invece di Sebbene
Suraj Jain

Quando si avvia una JVM e si carica una classe per la prima volta (questo viene fatto dal classloader quando si fa riferimento per la prima volta alla classe in qualsiasi modo), qualsiasi blocco o campo statico viene "caricato" nella JVM e diventa accessibile.
nhoxbypass

1
Sfortunatamente questa risposta contiene alcune imprecisioni di fatto su quando vengono inizializzate le statistiche. Consulta stackoverflow.com/a/3499322/139985 .
Stephen C

15

Vedere:

L'ultimo in particolare fornisce passaggi di inizializzazione dettagliati che spiegano quando le variabili statiche vengono inizializzate e in quale ordine (con l'avvertenza che finalle variabili di classe ei campi dell'interfaccia che sono costanti in fase di compilazione vengono inizializzati per primi).

Non sono sicuro di quale sia la tua domanda specifica sul punto 3 (supponendo che tu intenda quello annidato?). La sequenza dettagliata afferma che questa sarebbe una richiesta di inizializzazione ricorsiva, quindi continuerà l'inizializzazione.


12

I campi statici vengono inizializzati quando la classe viene caricata dal programma di caricamento classi. In questo momento vengono assegnati valori predefiniti. Questo viene fatto nell'ordine in cui appaiono nel codice sorgente.


10

L'ordine di inizializzazione è:

  1. Blocchi di inizializzazione statici
  2. Blocchi di inizializzazione dell'istanza
  3. Costruttori

I dettagli del processo sono spiegati nel documento delle specifiche JVM .


6

variabile statica

  • È una variabile che appartiene alla classe e non all'oggetto (istanza)
  • Le variabili statiche vengono inizializzate solo una volta, all'inizio dell'esecuzione (quando il Classloader carica la classe per la prima volta).
  • Queste variabili verranno inizializzate per prime, prima dell'inizializzazione di qualsiasi variabile di istanza
  • Una singola copia da condividere da tutte le istanze della classe
  • È possibile accedere a una variabile statica direttamente dal nome della classe e non necessita di alcun oggetto

4

A partire dal codice dell'altra domanda:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

Un riferimento a questa classe inizierà l'inizializzazione. Innanzitutto, la classe verrà contrassegnata come inizializzata. Quindi il primo campo statico verrà inizializzato con una nuova istanza di MyClass (). Notare che a myClass viene immediatamente fornito un riferimento a un'istanza MyClass vuota . Lo spazio è presente, ma tutti i valori sono nulli. Il costruttore viene ora eseguito e stampa obj, che è nullo.

Ora torniamo ad inizializzare la classe: objviene fatto un riferimento a un nuovo oggetto reale, e il gioco è fatto.

Se ciò è stato provocato da un'istruzione come: lo MyClass mc = new MyClass();spazio per una nuova istanza di MyClass viene nuovamente allocato (e il riferimento inserito mc). Il costruttore viene nuovamente eseguito e stampa di nuovo obj, che ora non è nullo.

Il vero trucco qui è che quando usi new, come in, WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weiiviene immediatamente dato un riferimento a un po 'di memoria annullata. La JVM procederà quindi a inizializzare i valori ed eseguire il costruttore. Ma se in qualche modo fai riferimento weii prima che lo faccia, facendo riferimento ad esso da un altro thread o o facendo riferimento all'inizializzazione della classe, ad esempio, stai guardando un'istanza di classe piena di valori nulli.


1
Una classe non viene contrassegnata come inizializzata fino al completamento dell'inizializzazione, altrimenti non avrebbe senso. Contrassegnare come inizializzato è quasi l' ultimo passaggio. Vedere JLS 12.4.2 .
Dave Newton

@ DaveNewton: una volta che qualcosa fa riferimento alla classe e inizia a inizializzarla, tutti gli ulteriori riferimenti tratteranno la classe come inizializzata. Non proveranno a inizializzarlo e non aspetteranno che venga inizializzato. Quindi i campi che sembrano non essere nulli dall'inizio di un programma possono effettivamente essere nulli per un certo periodo. Non capire questo è ciò che sta causando tutta la confusione. Penso che sia più semplice dire che una classe non inizializzata è "contrassegnata" come inizializzata al primo riferimento, tutti gli altri riferimenti la trattano come inizializzata, ed è per questo che questo accade.
RalphChapin

Una correzione al commento precedente: come descritto in JLS 12.4.2 di Dave Newton, la classe è bloccata durante l'inizializzazione. Altre discussioni saranno aspettare per la classe da inizializzare. Ciò non influisce su questo caso, tuttavia, che avviene tutto in un thread.
RalphChapin

4

La variabile statica può essere inizializzata nei tre modi seguenti: scegli quello che preferisci

  1. è possibile inizializzarlo al momento della dichiarazione
  2. oppure puoi farlo creando un blocco statico ad esempio:

    static {
            // whatever code is needed for initialization goes here
        }
    
  3. C'è un'alternativa ai blocchi statici: puoi scrivere un metodo statico privato

    class name {
        public static varType myVar = initializeVar();
    
        private static varType initializeVar() {
            // initialization code goes here
        }
    }
    
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.