Una guida alla parola chiave statica in Java

1. Introduzione

In questo articolo, esploreremo in dettaglio la parola chiave statica del linguaggio Java. Scopriremo come applicare la parola chiave static a variabili, metodi, blocchi, classi nidificate e quale differenza fa.

2. Anatomia della parola chiave statica

Nel linguaggio di programmazione Java, la parola chiave static indica che il particolare membro appartiene a un tipo stesso, piuttosto che a un'istanza di quel tipo .

Ciò significa che viene creata solo un'istanza di quel membro statico che viene condivisa tra tutte le istanze della classe.

La parola chiave può essere applicata a variabili, metodi, blocchi e classi nidificate.

3. I campi statici (o variabili di classe)

In Java, se un campo viene dichiarato statico , viene creata e condivisa esattamente una singola copia di quel campo tra tutte le istanze di quella classe . Non importa quante volte inizializziamo una classe; ci sarà sempre una sola copia del campo statico che gli appartiene. Il valore di questo campo statico sarà condiviso tra tutti gli oggetti dello stesso di qualsiasi classe diversa.

Dal punto di vista della memoria, le variabili statiche vanno in un particolare pool nella memoria JVM chiamato Metaspace (prima di Java 8, questo pool era chiamato Permanent Generation o PermGen, che è stato completamente rimosso e sostituito con Metaspace).

3.1. Esempio del campo statico

Supponiamo di avere una classe Car con diversi attributi (variabili di istanza) . Ogni volta che nuovi oggetti vengono inizializzati da questo progetto Car , ogni nuovo oggetto avrà la sua copia distinta di queste variabili di istanza.

Tuttavia, supponiamo di cercare una variabile che contenga il conteggio del numero di oggetti Car che vengono inizializzati e che sia condivisa tra tutte le istanze in modo che possano accedervi e incrementarla al momento dell'inizializzazione.

È qui che entrano in gioco le variabili statiche :

public class Car { private String name; private String engine; public static int numberOfCars; public Car(String name, String engine) { this.name = name; this.engine = engine; numberOfCars++; } // getters and setters }

Ora per ogni oggetto di questa classe che viene inizializzato, viene incrementata la stessa copia della variabile numberOfCars . Quindi, in questo caso, saranno vere le seguenti affermazioni:

@Test public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() { new Car("Jaguar", "V8"); new Car("Bugatti", "W16"); assertEquals(2, Car.numberOfCars); }

3.2. Motivi convincenti per utilizzare i campi statici

  • Quando il valore della variabile è indipendente dagli oggetti
  • Quando il valore dovrebbe essere condiviso tra tutti gli oggetti

3.3. Punti chiave da ricordare

  • Poiché le variabili statiche appartengono a una classe, è possibile accedervi direttamente utilizzando il nome della classe e non è necessario alcun riferimento a un oggetto
  • le variabili statiche possono essere dichiarate solo a livello di classe
  • è possibile accedere ai campi statici senza inizializzare gli oggetti
  • Sebbene possiamo accedere a campi statici utilizzando un riferimento a un oggetto (come ford.numberOfCars ++ ), dovremmo astenerci dall'usarlo poiché in questo caso diventa difficile capire se si tratta di una variabile di istanza o di una variabile di classe; invece, dovremmo sempre fare riferimento a variabili statiche usando il nome della classe (ad esempio, in questo caso, Car.numberOfCars ++ )

4. I metodi statici (o metodi di classe)

Simile a statici campi statici metodi anche appartenere ad una classe invece dell'oggetto, e così possono essere chiamati senza creare l'oggetto della classe in cui risiedono. Sono pensati per essere utilizzati senza creare oggetti della classe.

4.1. Esempio di metodo statico

i metodi statici vengono generalmente utilizzati per eseguire un'operazione che non dipende dalla creazione dell'istanza.

Se è presente un codice che dovrebbe essere condiviso tra tutte le istanze di quella classe, scrivi quel codice in un metodo statico :

public static void setNumberOfCars(int numberOfCars) { Car.numberOfCars = numberOfCars; }

i metodi statici sono anche ampiamente utilizzati per creare classi di utilità o di supporto in modo che possano essere ottenute senza creare un nuovo oggetto di queste classi.

Basta dare un'occhiata a Collections o Math utility classes da JDK, StringUtils da Apache o CollectionUtils dal framework Spring e nota che tutti i metodi sono statici .

4.2. Motivi convincenti per utilizzare metodi statici

  • Per accedere / manipolare variabili statiche e altri metodi statici che non dipendono dagli oggetti
  • i metodi statici sono ampiamente utilizzati nelle classi di utilità e di supporto

4.3. Punti chiave da ricordare

  • i metodi statici in Java vengono risolti in fase di compilazione. Poiché l'override del metodo fa parte del polimorfismo di runtime, i metodi statici non possono essere sostituiti
  • i metodi astratti non possono essere statici
  • i metodi statici non possono utilizzare questa o super parole chiave
  • Sono valide le seguenti combinazioni di istanza, metodi di classe e variabili:
    1. I metodi di istanza possono accedere direttamente sia ai metodi di istanza che alle variabili di istanza
    2. Metodi istanza può anche accedere statici variabili e statiche metodi direttamente
    3. i metodi statici possono accedere a tutte le variabili statiche e ad altri metodi statici
    4. i metodi statici non possono accedere direttamente alle variabili di istanza e ai metodi di istanza ; hanno bisogno di un riferimento a un oggetto per farlo

5. Un blocco statico

Un blocco statico viene utilizzato per inizializzare le variabili statiche . Sebbene le variabili statiche possano essere inizializzate direttamente durante la dichiarazione, ci sono situazioni in cui ci viene richiesto di eseguire l'elaborazione multilinea.

In questi casi, i blocchi statici sono utili.

Se le variabili statiche richiedono una logica aggiuntiva a più istruzioni durante l'inizializzazione, è possibile utilizzare un blocco statico .

5.1. L' esempio di blocco statico

Supponiamo di voler inizializzare un oggetto elenco con alcuni valori predefiniti.

Questo diventa facile con i blocchi statici :

public class StaticBlockDemo { public static List ranks = new LinkedList(); static { ranks.add("Lieutenant"); ranks.add("Captain"); ranks.add("Major"); } static { ranks.add("Colonel"); ranks.add("General"); } }

In questo esempio, non sarebbe possibile inizializzare l' oggetto List con tutti i valori iniziali insieme alla dichiarazione; ed è per questo che abbiamo utilizzato il blocco statico qui.

5.2. Motivi convincenti per utilizzare blocchi statici

  • Se l'inizializzazione delle variabili statiche richiede una logica aggiuntiva tranne l'assegnazione
  • If the initialization of static variables is error-prone and requires exception handling

5.3. Key Points to Remember

  • A class can have multiple static blocks
  • static fields and static blocks are resolved and executed in the same order as they are present in the class

6. A static Class

Java programming language allows us to create a class within a class. It provides a compelling way of grouping elements that are only going to be used in one place, this helps to keep our code more organized and readable.

The nested class architecture is divided into two:

  • nested classes that are declared static are called static nested classes whereas,
  • nested classes that are non-static are called inner classes

The main difference between these two is that the inner classes have access to all member of the enclosing class (including private), whereas the static nested classes only have access to static members of the outer class.

In fact, static nested classes behaved exactly like any other top-level class but enclosed in the only class which will access it, to provide better packaging convenience.

6.1. Example of static Class

The most widely used approach to create singleton objects is through static nested class is it doesn't require any synchronization and is easy to learn and implement:

public class Singleton { private Singleton() {} private static class SingletonHolder { public static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }

6.2. Compelling Reasons to Use a static Inner Class

  • Grouping classes that will be used only in one place increases encapsulation
  • The code is brought closer to the place that will be only one to use it; this increases readability and code is more maintainable
  • If nested class doesn't require any access to it's enclosing class instance members, then it's better to declare it as static because this way, it won't be coupled to the outer class and hence will be more optimal as they won't require any heap or stack memory

6.3. Key Points to Remember

  • static nested classes do not have access to any instance members of the enclosing outer class; it can only access them through an object's reference
  • le classi annidate statiche possono accedere a tutti i membri statici della classe che la racchiude, inclusi quelli privati
  • Le specifiche di programmazione Java non ci consentono di dichiarare la classe di primo livello come statica ; solo le classi all'interno delle classi (classi annidate) possono essere rese statiche

7. Conclusione

In questo articolo, abbiamo visto la parola chiave statica in azione. Leggiamo anche i motivi e i vantaggi dell'utilizzo di campi statici, metodi statici, blocchi statici e classi interne statiche.

Come sempre, possiamo trovare il codice completo su GitHub.