☕ Lezione 5

Metodi e Variabili Static - Membri di Classe

Static: Membri Condivisi tra Tutti gli Oggetti

🎯 Obiettivi della lezione

💡 Cosa significa Static?

Un membro static appartiene alla classe e non alle singole istanze (oggetti).

Significa che è condiviso tra tutti gli oggetti della classe.

Puoi accedere a un membro static anche senza creare oggetti!

🔍 Differenza: Static vs Istanza

Aspetto Membri di Istanza (normali) Membri Static
Appartenenza Ogni oggetto ha la sua copia Unica copia condivisa
Accesso oggetto.membro NomeClasse.membro
Creazione Quando creiamo un oggetto Quando viene caricata la classe
Serve l'oggetto? No

📝 Variabili Static: Esempio Base

public class Studente {
    // Variabile di ISTANZA - ogni studente ha la sua
    private String nome;
    private int eta;
    
    // Variabile STATIC - condivisa da tutti gli studenti
    private static int numeroStudenti = 0;
    
    // Costruttore
    public Studente(String nome, int eta) {
        this.nome = nome;
        this.eta = eta;
        numeroStudenti++;  // Incremento il contatore
    }
    
    // Metodo di istanza
    public void stampaInfo() {
        System.out.println("Nome: " + nome + ", Età: " + eta);
    }
    
    // Metodo STATIC per accedere alla variabile static
    public static int getNumeroStudenti() {
        return numeroStudenti;
    }
}
public class TestStudente {
    public static void main(String[] args) {
        // All'inizio non ci sono studenti
        System.out.println("Studenti totali: " + Studente.getNumeroStudenti());
        
        // Creo 3 studenti
        Studente s1 = new Studente("Mario", 17);
        Studente s2 = new Studente("Giulia", 16);
        Studente s3 = new Studente("Luca", 17);
        
        // Il contatore è aumentato!
        System.out.println("Studenti totali: " + Studente.getNumeroStudenti());
        
        // Creo un altro studente
        Studente s4 = new Studente("Anna", 18);
        
        System.out.println("Studenti totali: " + Studente.getNumeroStudenti());
    }
}
Studenti totali: 0 Studenti totali: 3 Studenti totali: 4

🎯 Punti chiave:

  • numeroStudenti è condiviso da tutti gli oggetti Studente
  • Ogni volta che creiamo uno studente, il contatore aumenta
  • Accediamo al metodo static con NomeClasse.metodo()
  • Non serve creare un oggetto per chiamare getNumeroStudenti()

🔧 Metodi Static

Un metodo static può essere chiamato senza creare un oggetto.

I metodi static NON possono accedere a membri di istanza direttamente.

📝 Esempio: Classe Calcolatrice

public class Calcolatrice {
    // Metodi static - non serve creare un oggetto Calcolatrice!
    
    public static int somma(int a, int b) {
        return a + b;
    }
    
    public static int sottrazione(int a, int b) {
        return a - b;
    }
    
    public static int moltiplicazione(int a, int b) {
        return a * b;
    }
    
    public static double divisione(double a, double b) {
        if (b != 0) {
            return a / b;
        } else {
            System.out.println("Errore: divisione per zero!");
            return 0;
        }
    }
    
    public static double potenza(double base, int esponente) {
        return Math.pow(base, esponente);
    }
    
    public static double radiceQuadrata(double numero) {
        if (numero >= 0) {
            return Math.sqrt(numero);
        } else {
            System.out.println("Errore: radice di numero negativo!");
            return 0;
        }
    }
}
public class TestCalcolatrice {
    public static void main(String[] args) {
        // Non serve creare un oggetto!
        // Uso direttamente NomeClasse.metodo()
        
        int risultato1 = Calcolatrice.somma(10, 5);
        System.out.println("10 + 5 = " + risultato1);
        
        int risultato2 = Calcolatrice.moltiplicazione(4, 7);
        System.out.println("4 * 7 = " + risultato2);
        
        double risultato3 = Calcolatrice.divisione(20, 4);
        System.out.println("20 / 4 = " + risultato3);
        
        double risultato4 = Calcolatrice.potenza(2, 10);
        System.out.println("2^10 = " + risultato4);
        
        double risultato5 = Calcolatrice.radiceQuadrata(144);
        System.out.println("√144 = " + risultato5);
    }
}
10 + 5 = 15 4 * 7 = 28 20 / 4 = 5.0 2^10 = 1024.0 √144 = 12.0

🔄 Simile alle funzioni del C!

I metodi static sono molto simili alle funzioni che usavi in C:

  • Non hanno bisogno di un "oggetto"
  • Prendono parametri e restituiscono risultati
  • Sono utilità indipendenti

La classe Math di Java contiene solo metodi static: Math.sqrt(), Math.pow(), etc.

🚫 Limitazioni dei Metodi Static

⚠️ Un metodo static NON può:

  • Accedere direttamente a variabili di istanza
  • Chiamare direttamente metodi di istanza
  • Usare la parola chiave this

Perché? Perché un metodo static può essere chiamato senza oggetti, quindi non sa a quale oggetto riferirsi!

public class Esempio {
    private int valore;  // Variabile di istanza
    private static int valoreStatic;  // Variabile static
    
    // Metodo static
    public static void metodoStatic() {
        // valore = 10;  // ERRORE! Non può accedere a variabili di istanza
        valoreStatic = 10;  // OK! Può accedere a variabili static
        
        // this.valore = 5;  // ERRORE! Non può usare this
    }
    
    // Metodo di istanza
    public void metodoIstanza() {
        valore = 10;  // OK! Può accedere a variabili di istanza
        valoreStatic = 10;  // OK! Può accedere anche a variabili static
    }
}

🔒 Costanti: final

La parola chiave final rende una variabile costante.

Una volta assegnato un valore, non può più essere modificato.

Le costanti si scrivono tipicamente in MAIUSCOLO con underscore.

public class Configurazione {
    // Costanti pubbliche e static
    public static final double PI_GRECO = 3.14159;
    public static final int MAX_STUDENTI = 30;
    public static final String NOME_SCUOLA = "Liceo Scientifico";
    public static final double IVA = 0.22;  // 22%
    
    // Metodo che usa le costanti
    public static double calcolaPrezzoConIva(double prezzoBase) {
        return prezzoBase * (1 + IVA);
    }
}
public class TestConfigrazione {
    public static void main(String[] args) {
        System.out.println("Scuola: " + Configurazione.NOME_SCUOLA);
        System.out.println("Max studenti: " + Configurazione.MAX_STUDENTI);
        System.out.println("Pi greco: " + Configurazione.PI_GRECO);
        
        double prezzo = 100;
        double prezzoFinale = Configurazione.calcolaPrezzoConIva(prezzo);
        System.out.println("Prezzo base: €" + prezzo);
        System.out.println("Prezzo con IVA: €" + prezzoFinale);
        
        // Configurazione.IVA = 0.30;  // ERRORE! È final!
    }
}
Scuola: Liceo Scientifico Max studenti: 30 Pi greco: 3.14159 Prezzo base: €100.0 Prezzo con IVA: €122.0

🏦 Esempio Completo: Classe BancaCentrale

public class BancaCentrale {
    // Costanti
    public static final double TASSO_INTERESSE = 0.02;  // 2%
    public static final double LIMITE_PRELIEVO = 500.0;
    
    // Variabile static per contare i conti
    private static int numeroConti = 0;
    
    // Attributi di istanza
    private String numeroConto;
    private String intestatario;
    private double saldo;
    
    // Costruttore
    public BancaCentrale(String intestatario, double saldoIniziale) {
        numeroConti++;
        this.numeroConto = "IT" + numeroConti;
        this.intestatario = intestatario;
        this.saldo = saldoIniziale;
    }
    
    // Metodo di istanza
    public void applicaInteressi() {
        double interessi = saldo * TASSO_INTERESSE;
        saldo += interessi;
        System.out.println("Interessi applicati: €" + interessi);
    }
    
    // Metodo di istanza
    public boolean preleva(double importo) {
        if (importo > LIMITE_PRELIEVO) {
            System.out.println("Impossibile! Limite prelievo: €" + LIMITE_PRELIEVO);
            return false;
        }
        
        if (saldo >= importo) {
            saldo -= importo;
            System.out.println("Prelevati €" + importo);
            return true;
        } else {
            System.out.println("Saldo insufficiente!");
            return false;
        }
    }
    
    // Metodo di istanza
    public void stampaSaldo() {
        System.out.println(intestatario + " - Saldo: €" + saldo);
    }
    
    // Metodo static
    public static int getNumeroConti() {
        return numeroConti;
    }
    
    // Metodo static per convertire valuta
    public static double convertiInDollari(double euro, double tassioCambio) {
        return euro * tassioCambio;
    }
}
public class TestBanca {
    public static void main(String[] args) {
        System.out.println("Conti totali: " + BancaCentrale.getNumeroConti());
        System.out.println("Tasso interesse: " + (BancaCentrale.TASSO_INTERESSE * 100) + "%");
        System.out.println();
        
        BancaCentrale conto1 = new BancaCentrale("Mario Rossi", 1000);
        BancaCentrale conto2 = new BancaCentrale("Giulia Bianchi", 5000);
        
        System.out.println("Conti totali: " + BancaCentrale.getNumeroConti());
        System.out.println();
        
        conto1.stampaSaldo();
        conto1.applicaInteressi();
        conto1.stampaSaldo();
        System.out.println();
        
        conto1.preleva(300);  // OK
        conto1.preleva(600);  // Supera il limite!
        System.out.println();
        
        // Uso metodo static per conversione
        double euro = 1000;
        double dollari = BancaCentrale.convertiInDollari(euro, 1.10);
        System.out.println("€" + euro + " = $" + dollari);
    }
}
Conti totali: 0 Tasso interesse: 2.0% Conti totali: 2 Mario Rossi - Saldo: €1000.0 Interessi applicati: €20.0 Mario Rossi - Saldo: €1020.0 Prelevati €300.0 Impossibile! Limite prelievo: €500.0 €1000.0 = $1100.0

✏️ Esercizi Guidati

Esercizio 1: Contatore Auto

FACILE

Obiettivo: Creare una classe Auto che conta quante auto sono state create.

Requisiti:

  • Attributi di istanza: marca, modello
  • Variabile static: numeroAuto (contatore)
  • Costruttore che incrementa il contatore
  • Metodo static getNumeroAuto()
  • Nel main, crea 5 auto e stampa il totale

Esercizio 2: Classe Matematica

MEDIO

Obiettivo: Creare una classe con metodi static per operazioni matematiche.

Requisiti:

  • Metodo static massimo(int a, int b) che restituisce il maggiore
  • Metodo static minimo(int a, int b)
  • Metodo static pari(int n) che restituisce true se pari
  • Metodo static fattoriale(int n)
  • Costante E_NEPERO = 2.71828

💪 Esercizi da Svolgere

Esercizio 3: Convertitore Unità

FACILE

Crea una classe ConvertitoreUnita con metodi static per:

  • kmInMiglia(double km)
  • celsiusInFahrenheit(double celsius)
  • kgInLibbre(double kg)

Esercizio 4: Classe Prodotto con Codice

MEDIO

Crea una classe Prodotto che assegna automaticamente un codice progressivo:

  • Variabile static per il contatore
  • Attributo di istanza: codice (generato automaticamente)
  • Il codice deve essere "PROD001", "PROD002", etc.

Esercizio 5: Validatore

MEDIO

Crea una classe Validatore con metodi static per validare:

  • isEmailValida(String email) - controlla che contenga @ e .
  • isCodiceFiscaleValido(String cf) - controlla che sia lungo 16 caratteri
  • isTelefonoValido(String tel) - controlla che sia lungo 10 cifre

🎯 Concetti Chiave da Ricordare

  • static = appartiene alla classe, non agli oggetti
  • Variabili static sono condivise tra tutti gli oggetti
  • Metodi static si chiamano con NomeClasse.metodo()
  • Metodi static NON possono accedere a membri di istanza
  • final = costante, non modificabile
  • Costanti: public static final NOME_COSTANTE
  • La classe Math usa solo metodi static

📚 Quando Usare Static?

✅ Usa static per:

  • Metodi di utilità (come Calcolatrice, Validatore)
  • Contatori condivisi
  • Costanti (sempre con final)
  • Factory methods

❌ NON usare static per:

  • Dati specifici di ogni oggetto
  • Metodi che devono accedere a attributi di istanza
  • Quando hai bisogno del polimorfismo (lo vedremo)