Dubbio su attributi di classe

di il
12 risposte

Dubbio su attributi di classe

Ciao! Sul buon De Sio Cesari ho trovato un costrutto che mi ha lasciato perplesso, nel capitolo sulle enumerazioni. Per non farvela troppo lunga questo è quanto:

public class Azione {
private String nome;
public static final Azione AVANTI = new
Azione("AVANTI");
public static final Azione INDIETRO = new
Azione("INDIETRO");
public static final Azione FERMO = new
Azione("FERMO");
public Azione(String nome){
setNome(nome);
}
public void setNome(String nome) {
this.nome = nome;
}
public String getNome(){
return this.nome;
}
}

La cosa che non capisco è perchè si possano mettere delle "istanziazioni" della classe Azione all'interno degli attributi della classe stessa. Tra l'altro utilizza la forma Azione("AVANTI") senza avere introdotto un costruttore Azione(String). Scusate il mio linguaggio terra terra, spero sia chiaro .
In pratica, se non ho capito male, alla fine il risultato è che la classe potrà assumere solo i tre valori "AVANTI", "INDIETRO" e "FERMO".

12 Risposte

  • Re: Dubbio su attributi di classe

    ciamba87 ha scritto:


    La cosa che non capisco è perchè si possano mettere delle "istanziazioni" della classe Azione all'interno degli attributi della classe stessa.
    È perfettamente lecito e tecnicamente corretto. Essendo poi quei campi "di classe" (static) non ci sono problemi nella sequenza di inizializzazione degli oggetti istanziati.
    Ci sarebbero problemi (grossi problemi ....) se il campo fosse "di istanza".

    Se provi questo:
    public class Prova {
        private Prova p = new Prova();
    
        public Prova() {
            System.out.println("costruttore Prova");
        }
    }
    E poi da qualche parte (in Prova o altrove) fai un new Prova(); ti accorgi subito che ti becchi un bel StackOverflowError, ovvero lo stack "scoppia".
    Tu istanzi un Prova ma la inizializzazione del campo 'p' porta ad un nuovo oggetto Prova che di nuovo deve inizializzare il suo campo 'p' e quindi un nuovo Prova ecc......
    Questo infatti è SBAGLIATO.

    ciamba87 ha scritto:


    Tra l'altro utilizza la forma Azione("AVANTI") senza avere introdotto un costruttore Azione(String).
    NON ha importanza dove si trova lessicalmente nella classe il costruttore. Potrebbe stare dopo (come nell'esempio) o prima di quei campi static.
    Il costruttore c'è, esiste e può essere invocato.

    ciamba87 ha scritto:


    In pratica, se non ho capito male, alla fine il risultato è che la classe potrà assumere solo i tre valori "AVANTI", "INDIETRO" e "FERMO".
    . Quel codice è qualcosa che tenta, in un certo senso, di avvicinarsi al concetto di una enum (dove ci sono solo N istanze esatte che sono quelle assegnate alle costanti della enum) ma in realtà è "troppo aperta". Il costruttore è public (quindi invocabile ovunque e da qualunque codice) e oltretutto c'è il setter setNome, quindi lo stato è pure "mutabile".

    Insomma, è parecchio lontano dal concetto delle enum!
  • Re: Dubbio su attributi di classe

    Hai colto in pieno il mio dubbio però non riesco ancora a capire: forse ho ancora poco chiaro l'attributo static però cos'è che mi permette di non incappare in quel "loop" che produce lo StackOverFlow e che tu hai perfettamente descritto? La presenza dell'attributo static?
  • Re: Dubbio su attributi di classe

    Considera questo:
    ci sono DUE momenti da prendere in considerazione, anzi 3:
    1) la classe VIENE COMPILATA, quindi viene generato il codice dei metodi e le informazioni sui membri
    2) la classe viene CARICATA, e SOLO IN QUESTO MOMENTO viene ESEGUITO il codice relativo ai membri STATICI della classe ed il COSTRUTTORE DI CLASSE (un pezzetto di codice dentro static {... })
    2) viene creata un'ISTANZA di quella classe, ed in questo momento viene ESEGUITO il costruttore DI ISTANZA (il costruttore classico)

    Quindi, negli istanti 2) e 3) i metodi della classe esistono gia', anche se la loro DEFINIZIONE si trova nel posto VISIVAMENTE sbagliato (DOPO essere stati utilizzati)
  • Re: Dubbio su attributi di classe

    Ok, grazie migliorabile. La cosa che ancora non mi torna però è:
    Supponiamo che io crei la classe col main
    
    public class Principale{
    	public static void main(String[] args)
    	{
    	Azione prova=new Azione();
    	prova.getNome("Agisci");
    	}
    	 
    
    sarebbe sbagliato? Cosa gli impedisce di entrare nel "loop" che provoca la creazione delle tre istanze di Azione (AVANTI, INDIETRO, FERMO), ognuna seguita dalla creazione di tre istanze di azione...e così via? C'entra l'attributo static?
  • Re: Dubbio su attributi di classe

    ciamba87 ha scritto:


    sarebbe sbagliato?
    La istanziazione è sbagliata (manca un argomento) ed è sbagliato anche l'uso di getNome, dato che è un "getter" e non ha parametri (anche per il codice postato prima).

    ciamba87 ha scritto:


    Cosa gli impedisce di entrare nel "loop" che provoca la creazione delle tre istanze di Azione (AVANTI, INDIETRO, FERMO), ognuna seguita dalla creazione di tre istanze di azione...e così via? C'entra l'attributo static?
    Sì, c'entra. Un membro "di classe" (static) è associato concettualmente alla classe, NON distintamente a ciascun oggetto della classe. Un campo static quindi è "unico", globale rispetto a tutti gli oggetti.
  • Re: Dubbio su attributi di classe

    Sì, scusa ho tirato giù un codice senza nemmeno testarlo su eclipse.
    Comunque mi accorgo che l'utilizzo di static non mi è ancora chiaro, nonostante col De Sio Cesari mi trovi abbastanza bene. Avreste qualche testo/link/tutorial che mi consigliereste per capirlo?
  • Re: Dubbio su attributi di classe

    Non cercare complicazioni dove non ci sono: static serve per indicare che quel metodo/membro e' il classico staticone, alias globalone, creato UNA ed UNA SOLA VOLTA al CARICAMENTO della classe.

    Se conosci il C, static int variabile; e' la solita variabile golbale, mentre il metodo static void mmm(int x){ ... } e' esattamente come la defizione della funzione.

    Fai cosi':

    definisci una classe con DUE membri di tipo intero, uno STATICO ed uno no. Quindi, nel COSTRUTTORE (di ISTANZA) incrementi di 1 membri e li stampi.

    a questo punto fai un ciclo (per 10 volte) che istanzia un oggetto della classe, e OSSERVA che succede.
  • Re: Dubbio su attributi di classe

    Ricorro ancora ad un modo banale di scrivere, non me ne vogliate: se io metto l'attributo static è un po' come se la classe stessa fosse "inizializzata" con il comando successivo; nel momento in cui vado a istanziare la classe le parti static è come se "fossero già state eseguite in precedenza" e quindi non cado nel loop perchè non vengono ripetute nuovamente.
    Ha senso?
  • Re: Dubbio su attributi di classe

    ciamba87 ha scritto:


    se io metto l'attributo static è un po' come se la classe stessa fosse "inizializzata" con il comando successivo;
    Detto così ha poco senso. Non cercare di complicare quello che, invece, così complicato non lo è.
    Un membro static di una classe e in modo specifico un campo static è UNICO, ne hai solo uno e non dipende da quali/quante istanze ci sono della classe.
    Sono i campi di istanza (non static) che invece sono "per oggetto". Se una classe Persona ha campi di istanza nome e cognome, allora ciascun oggetto Persona ha i SUOI propri campi nome e cognome. Ogni oggetto potrà avere nome/cognome differenti. Ma un campo statico è uno solo, "globale" rispetto a tutte le istanze.

    Domanda: hai fatto la prova suggerita da migliorabile?

    Ecco un'altra prova utile:
    public class ProvaStatic {
        private static int sval = setup();
    
        static {
            System.out.println("--blocco di inizializzazione static--");
        }
    
        private static int setup() {
            System.out.println("--setup--");
            return 123;
        }
    
        public static void main(String[] args) {
            System.out.println("--main--");
        }
    }
  • Re: Dubbio su attributi di classe

    Penso che dovrò un po' usarlo in vari contesti per capirlo a fondo, questo static. Ho fatto l'esempio di migliorabile:
    
    public class StaticClass 
    {	
    static int a=1;
    int b=1;
    
    public StaticClass()
    {
    {
    		
    	System.out.println("a="+a);
    	System.out.println("b="+b);
    	b=1;
    	a++;
    	b++;
    	}
    	
    }
    }
    
    e
    
    public class MainClass 
    {
    public static void main(String[] args) 
    {
    for(int i=1;i<=10;i++)
    {
    StaticClass prova=new StaticClass();
    }
    	
    }
    }
    
    e vedo incrementare a e rimanere fermo b, questo significa che a è proprio della classe e b è proprio dell'istanza.

    Molto curioso è l'esempio di andbin, che ho anche modificato in questo modo:
    
    public class NonStatic 
    {
    private int sval=setup();
    {
    	System.out.println("--blocco di inizializzazione--");
    }
    private int setup()
    {
    	System.out.println("--setup--");
    	return 123;
    	
    }
    public static void main(String[] args) 
    {
    	System.out.println("--main--");
    }
    }
    
    La cosa che mi ha incuriosito di questo esempio è che, nella forma in cui me lo hai suggerito, stampi tutte le righe di testo anche se la classe ProvaStatic non è direttamente richiamata nel main. Invece nella forma in cui l'ho modificato (NonStatic) stampa solo "--main--". Non ho ancora chiaro il perchè, spero, a questo punto, di capirlo con la pratica.
  • Re: Dubbio su attributi di classe

    ciamba87 ha scritto:


    questo significa che a è proprio della classe e b è proprio dell'istanza.
    Appunto. La variabile a è "di classe", associata alla classe, quindi "globale" ed è indifferente al numero di oggetti istanziati di quella classe. Non c'entra proprio nulla con gli oggetti istanziati, insomma.
    La variabile b invece è "di istanza", ciascun oggetto della classe ha la SUA variabile b, distinta da quella degli altri oggetti.

    ciamba87 ha scritto:


    La cosa che mi ha incuriosito di questo esempio è che, nella forma in cui me lo hai suggerito, stampi tutte le righe di testo anche se la classe ProvaStatic non è direttamente richiamata nel main.
    Il codice che ho scritto prima mostra una cosa importante: gli inizializzatori delle variabili static (nel codice quel sval = .....) e gli static initialization blocks ("blocchi di inizializzazione static") vengono eseguiti poco dopo che la classe è stata caricata in memoria e comunque PRIMA di qualunque "uso" della classe da parte di altre classi. E viene fatto UNA volta sola dalla JVM.

    E questo tra l'altro avviene anche PRIMA che la JVM vada ad invocare il main(String[] args).

    ciamba87 ha scritto:


    Invece nella forma in cui l'ho modificato (NonStatic) stampa solo "--main--". Non ho ancora chiaro il perchè, spero, a questo punto, di capirlo con la pratica.
    Hai messo un instance initialization block e poi hai reso sval "di istanza". La esecuzione di questi avverrebbe solo creando una istanza della classe. Cosa che non c'è e quindi è ovvio che quel setup e quel blocco non vengono invocati!
  • Re: Dubbio su attributi di classe

    Ok, grazie mille
Devi accedere o registrarti per scrivere nel forum
12 risposte