Chi, avvicinandosi per la prima volta al linguaggio Java, non è incappato nel famigerato errore di compilazione che recita “non static variable x cannot be referenced from a static context“? Chi conosce bene la programmazione Object Oriented (per esperienza con tale linguaggio o anche per provenienza da altri linguaggi) solitamente si fa una risatina, magari si dà pure una pacca sulla testa e va immediatamente a correggere l’errore, senza battere ciglio. Altri, invece, si trovano a combattere ogni volta una guerra personale contro questo errore.

Per questo ho deciso di scrivere il seguente articolo: dare la possibilità a chi non è pratico di Java (e, in generale, di Object Oriented Programming, OOP) di capire perchè salta fuori questo errore e, conseguentemente, come andarlo a correggere,spiegando il significato del modificatore static.

Partiamo subito da un esempio, banalissimo, che genera questo genere di errori:

public class Prova {
private int i;
public static void main(String [] args) {
i = 0;
}
}

Questo semplice ed inutile programma genera l’errore di cui parliamo qui. Perché? “Semplice!”, direbbe colui che mastica pane e Java dalla mattina alla sera, “perchè stiamo facendo riferimento ad una variabile non statica dall’interno di un contesto statico!”. Cerchiamo, quindi, di capire cosa vuol dire questa frase, partendo dall’inizio.La parola oggetto può assumere due significati diversi: può significare classe oppure istanza. Non lasciamoci intimorire da questa cosa. La classe è l’insieme delle proprietà e dei comportamenti che si possono definire per una categoria di cose (utilizzo il termine cose al posto del termine oggetto per non confondere). L’istanza di una classe è una particolare cosa. Facciamo un esempio per chiarirci bene le idee; un triangolo è una figura geometrica che ha delle caratteristiche ben note: tre lati, una base e un’altezza. Triangolo, quindi, è la classe che definisce tute le cose che hanno queste caratteristiche. Il triangolo t di base 3 e altezza 4 è un’istanza della classe Triangolo. Nel linguaggio colloquiale si usa il termine oggetto per identificare sia la classe (che oggetto è? è un triangolo!), sia l’istanza della classe (quale oggetto stai misurando? l’oggetto t, quello con base 3 e altezza 4) e questo, nella pratica, genera l’errore di cui stiamo parlando.

Nella programmazione Object Oriented, infatti, è possibile stabilire delle proprietà o dei comportamenti (metodi) che sono validi per tutte le istanze della classe o solo per ciascuna istanza specifica; continuando con l’esempio del triangolo, una caratteristica comune a tutti i triangoli è quella di avere la somma degli angoli interni sempre uguale a 180 gradi, mentre una caratteristica che varia da trinagolo a triangolo è, ad esempio, l’altezza. Da questo potremmo dire che la proprietà “somma degli angoli interni” è una proprietà di classe, mentre la proprietà “altezza” è una proprietà di istanza.

Il modificatore static fa proprio questo. Serve ad indicare che la proprietà o il metodo che stiamo dichiarando è di classe e non di istanza. Questo ha delle ripercussioni sulla semantica della proprietà o del metodo: se un metodo (o una proprietà) è di classe, esso esiste a prescindere da tutte le istanze di quella classe; viceversa, se un metodo (o una proprietà) è di istanza, per esistere esso ha bisogno che venga istanziato un oggetto di quella classe. Ed il discorso è ovvio: per poter lavorare con l’altezza di un triangolo io devo lavorare su uno specifico triangolo, mentre per poter lavorare sulla somma dei suoi angoli interni non ho bisogno di nulla, solo della classe. In codice, questo si traduce nelle seguenti due forme di invocazione del metodo (o della proprietà):


// Richiamo un metodo di classe
NomeClasse.metodo();


// Richiamo un metodo di istanza
NomeClasse oggetto = new NomeClasse( ... );
oggetto.metodo();

Come si può vedere, l’invocazione di un metodo statico (di classe, quindi) avviene anteponendo solo il nome della classe (nell’esempio “NomeClasse”), mentre l’invocazione di un metodo non statico (di istanza, quindi) deve avvenire solo su oggetti della classe, precedentemente istanziato tramite l’operatore new. L’errore di compilazione “non static variable … cannot be referenced from a static context”, quindi, viene sollevata ogni volta che tentiamo di utilizzare un metodo o una proprietà di istanza dall’interno di un contesto (metodo o blocco) di classe. Non è possibile, da un contesto di classe, fare riferimento a qualcosa che riguarda strettamente una singola istanza, perchè la classe non ne è a conoscenza. Al contrario, invece, tutte le istanze possono far uso di proprietà e metodi statici, poichè esse riguardano la loro classe.

Tornando, quindi, al programma d’esempio postato inizialmente, possiamo facilmente comprendere perchè dal main (che è un contesto statico) non possiamo riferirci alla variabile i: essa non è statica, quindi è legata ad una particolare istanza della classe ed è utilizzabile solo dall’istanza specifica. La correzione è ovvia: è sufficiente apporre il modificatore static alla variabile, ma non sempre le cose sono così semplici; dipende sempre da quale significato diamo ai vari membri.

Per chiudere il discorso, lo stesso problema si verifica quando cerchiamo di utilizzare dei metodi non statici all’interno di contesti statici. La logica è sempre la stessa, ma il messaggio d’errore cambia leggermente e potrebbe spiazzare chi è alle prime armi: “non-static variable this cannot be referenced from a static context”. Di questo simpatico/antipatico signore chiamato this parleremo più avanti in un altro articolo.

LeleFT

Tags: