Salta al contenuto principale

04 - OOP: Concetti Fondamentali

Programmazione a oggetti in Java: classi, oggetti, costruttori, incapsulamento, modificatori di accesso, this e membri statici.

Cosa ne pensi di questo articolo?

04 - OOP: Concetti Fondamentali
JavaFoto:Godfrey AtimaPexels

In Breve

Programmazione a oggetti in Java: classi, oggetti, costruttori, incapsulamento, modificatori di accesso, this e membri statici.

Programmazione Orientata agli Oggetti

La Programmazione Orientata agli Oggetti (OOP) è un paradigma che modella il software come una collezione di oggetti che interagiscono tra loro. Ogni oggetto rappresenta un'entità del mondo reale con stato (attributi) e comportamento (metodi).

Cosa Imparerai

  • Cos'è una classe e cos'è un oggetto
  • Stato e comportamento
  • Costruttori e inizializzazione
  • Incapsulamento e modificatori di accesso
  • La parola chiave this
  • Membri statici vs di istanza

Classi e Oggetti

Definizioni Chiave

  • Classe: Un modello (blueprint) che definisce attributi e metodi
  • Oggetto: Un'istanza di una classe, un'entità concreta in memoria
  • Attributi: Variabili che rappresentano lo stato dell'oggetto
  • Metodi: Funzioni che definiscono il comportamento dell'oggetto
Prima Classe: Studente
// Definizione della classe
public class Studente {
    // Attributi (stato)
    String nome;
    String cognome;
    int matricola;
    int annoCorso;
    double mediaVoti;

    // Metodi (comportamento)
    void presentati() {
        System.out.println("Ciao, sono " + nome + " " + cognome);
        System.out.println("Matricola: " + matricola);
    }

    void studiaMateria(String materia) {
        System.out.println(nome + " sta studiando " + materia);
    }

    boolean isFuoriCorso() {
        return annoCorso > 3;
    }
}
Creare e Usare Oggetti
public class Main {
    public static void main(String[] args) {
        // Creazione oggetto con new
        Studente mario = new Studente();

        // Assegnazione attributi
        mario.nome = "Mario";
        mario.cognome = "Rossi";
        mario.matricola = 123456;
        mario.annoCorso = 2;
        mario.mediaVoti = 27.5;

        // Chiamata metodi
        mario.presentati();
        mario.studiaMateria("Programmazione");

        // Creare più oggetti dalla stessa classe
        Studente luigi = new Studente();
        luigi.nome = "Luigi";
        luigi.cognome = "Verdi";
        luigi.matricola = 789012;

        // Ogni oggetto ha il proprio stato
        System.out.println(mario.nome);  // Mario
        System.out.println(luigi.nome);  // Luigi
    }
}

Costruttori

Un costruttore e un metodo speciale chiamato quando si crea un oggetto con new. Permette di inizializzare l'oggetto.

Costruttori
public class Studente {
    String nome;
    String cognome;
    int matricola;
    int annoCorso;

    // Costruttore di default (senza parametri)
    public Studente() {
        this.annoCorso = 1; // valore predefinito
    }

    // Costruttore con parametri
    public Studente(String nome, String cognome, int matricola) {
        this.nome = nome;
        this.cognome = cognome;
        this.matricola = matricola;
        this.annoCorso = 1;
    }

    // Costruttore completo
    public Studente(String nome, String cognome, int matricola, int annoCorso) {
        this.nome = nome;
        this.cognome = cognome;
        this.matricola = matricola;
        this.annoCorso = annoCorso;
    }
}

// Utilizzo dei costruttori
Studente s1 = new Studente();                           // costruttore di default
Studente s2 = new Studente("Mario", "Rossi", 123456);   // costruttore con 3 parametri
Studente s3 = new Studente("Luigi", "Verdi", 789012, 2); // costruttore completo

Regole sui Costruttori

  • Il nome del costruttore deve essere identico al nome della classe
  • Non ha tipo di ritorno (nemmeno void)
  • Se non definisci nessun costruttore, Java crea un costruttore di default vuoto
  • Se definisci un costruttore con parametri, il costruttore di default non viene più creato automaticamente

Incapsulamento

L'incapsulamento protegge i dati di un oggetto nascondendoli dall'esterno e fornendo metodi controllati per accedervi (getter/setter).

Modificatori di Accesso
public class ContoBancario {
    // private: accessibile solo dentro la classe
    private double saldo;
    private String intestatario;

    // public: accessibile da ovunque
    public ContoBancario(String intestatario, double saldoIniziale) {
        this.intestatario = intestatario;
        this.saldo = saldoIniziale;
    }

    // Getter: permette di LEGGERE il valore
    public double getSaldo() {
        return saldo;
    }

    public String getIntestatario() {
        return intestatario;
    }

    // Setter con validazione
    public void deposita(double importo) {
        if (importo > 0) {
            saldo += importo;
            System.out.println("Depositati €" + importo);
        } else {
            System.out.println("Importo non valido");
        }
    }

    public boolean preleva(double importo) {
        if (importo > 0 && importo <= saldo) {
            saldo -= importo;
            System.out.println("Prelevati €" + importo);
            return true;
        }
        System.out.println("Prelievo non autorizzato");
        return false;
    }
}

Modificatori di Accesso

Modificatore Classe Package Sottoclasse Ovunque
private ✅ ❌ ❌ ❌
(default) ✅ ✅ ❌ ❌
protected ✅ ✅ ✅ ❌
public ✅ ✅ ✅ ✅

La Parola Chiave this

Uso di this
public class Corso {
    private String nome;
    private int crediti;
    private Docente docente;

    // this per distinguere parametri da attributi
    public Corso(String nome, int crediti) {
        this.nome = nome;       // this.nome = attributo
        this.crediti = crediti; // nome = parametro
    }

    // this per chiamare un altro costruttore
    public Corso(String nome) {
        this(nome, 6); // chiama il costruttore con 2 parametri
    }

    // this per passare l'oggetto corrente
    public void assegnaDocente(Docente docente) {
        this.docente = docente;
        docente.aggiungiCorso(this); // passa questo corso al docente
    }

    // this per catene di metodi (fluent interface)
    public Corso conCrediti(int crediti) {
        this.crediti = crediti;
        return this;
    }

    public Corso conDocente(Docente docente) {
        this.docente = docente;
        return this;
    }
}

// Uso fluent interface
Corso corso = new Corso("Programmazione")
    .conCrediti(9)
    .conDocente(profRossi);

Membri Statici vs Istanza

static keyword
public class Studente {
    // Attributo STATICO: condiviso da tutte le istanze
    private static int contatore = 0;
    private static final String UNIVERSITA = "Universita di Bologna";

    // Attributi di ISTANZA: uno per ogni oggetto
    private int matricola;
    private String nome;

    public Studente(String nome) {
        this.nome = nome;
        contatore++;                    // incrementa per ogni nuovo studente
        this.matricola = 2024000 + contatore;
    }

    // Metodo STATICO: appartiene alla classe, non all'istanza
    public static int getNumeroStudenti() {
        return contatore;
    }

    public static String getUniversita() {
        return UNIVERSITA;
    }

    // Metodo di ISTANZA: opera su un oggetto specifico
    public void presentati() {
        System.out.println("Sono " + nome + " di " + UNIVERSITA);
    }
}

// Utilizzo
System.out.println(Studente.getUniversita()); // Chiamata statica

Studente s1 = new Studente("Mario");
Studente s2 = new Studente("Luigi");

System.out.println(Studente.getNumeroStudenti()); // 2
s1.presentati(); // Chiamata su istanza

Quando usare static

  • Costanti: static final per valori immutabili condivisi
  • Contatori: Per tenere traccia del numero di istanze
  • Utility: Metodi che non dipendono dallo stato dell'oggetto (es. Math.sqrt())
  • Factory: Metodi che creano istanze della classe

Esempio Completo: Sistema Gestione Corsi

Classe Studente
package it.universita.gestione;

public class Studente {
    // Attributi statici
    private static int contatore = 0;

    // Attributi di istanza
    private final int matricola;
    private String nome;
    private String cognome;
    private int annoIscrizione;
    private double mediaVoti;
    private int esamiSostenuti;

    // Costruttore
    public Studente(String nome, String cognome, int annoIscrizione) {
        this.matricola = generaMatricola();
        this.nome = nome;
        this.cognome = cognome;
        this.annoIscrizione = annoIscrizione;
        this.mediaVoti = 0;
        this.esamiSostenuti = 0;
    }

    // Metodo statico privato
    private static int generaMatricola() {
        contatore++;
        return 2024000 + contatore;
    }

    // Getter
    public int getMatricola() {
        return matricola;
    }

    public String getNomeCompleto() {
        return nome + " " + cognome;
    }

    public double getMediaVoti() {
        return mediaVoti;
    }

    // Metodo per registrare un esame
    public void registraEsame(int voto) {
        if (voto >= 18 && voto <= 30) {
            double totale = mediaVoti * esamiSostenuti;
            esamiSostenuti++;
            mediaVoti = (totale + voto) / esamiSostenuti;
            System.out.printf("%s ha superato l'esame con %d%n", getNomeCompleto(), voto);
        } else {
            System.out.println("Voto non valido");
        }
    }

    // Metodo per calcolare l'anno di corso
    public int getAnnoCorso() {
        int annoCorrente = java.time.Year.now().getValue();
        return annoCorrente - annoIscrizione + 1;
    }

    public boolean isFuoriCorso() {
        return getAnnoCorso() > 3;
    }

    // toString per rappresentazione stringa
    @Override
    public String toString() {
        return String.format("Studente[matricola=%d, nome=%s, media=%.2f, anno=%d]",
            matricola, getNomeCompleto(), mediaVoti, getAnnoCorso());
    }

    // Metodo statico di utilita
    public static int getTotaleStudenti() {
        return contatore;
    }
}
Classe Esame
package it.universita.gestione;

public class Esame {
    private String nomeCorso;
    private int crediti;
    private Studente studente;
    private int voto;
    private boolean lode;
    private String data;

    public Esame(String nomeCorso, int crediti, Studente studente) {
        this.nomeCorso = nomeCorso;
        this.crediti = crediti;
        this.studente = studente;
    }

    public void registraVoto(int voto, boolean lode) {
        if (voto >= 18 && voto <= 30) {
            this.voto = voto;
            this.lode = (voto == 30 && lode);
            this.data = java.time.LocalDate.now().toString();
            studente.registraEsame(voto);
        }
    }

    public String getVotoFormattato() {
        if (voto == 0) return "Non sostenuto";
        return lode ? "30 e Lode" : String.valueOf(voto);
    }

    @Override
    public String toString() {
        return String.format("%s - %s: %s (%d CFU)",
            studente.getNomeCompleto(), nomeCorso, getVotoFormattato(), crediti);
    }
}
Main di Test
package it.universita.gestione;

public class TestGestione {
    public static void main(String[] args) {
        // Creazione studenti
        Studente mario = new Studente("Mario", "Rossi", 2023);
        Studente luigi = new Studente("Luigi", "Verdi", 2022);

        // Registrazione esami
        Esame esameProgrammazione = new Esame("Programmazione", 9, mario);
        esameProgrammazione.registraVoto(28, false);

        Esame esameAnalisi = new Esame("Analisi I", 12, mario);
        esameAnalisi.registraVoto(30, true);

        Esame esameReti = new Esame("Reti", 6, luigi);
        esameReti.registraVoto(25, false);

        // Stampa situazione
        System.out.println("\n=== Situazione Studenti ===");
        System.out.println(mario);
        System.out.println(luigi);

        System.out.println("\n=== Esami Registrati ===");
        System.out.println(esameProgrammazione);
        System.out.println(esameAnalisi);
        System.out.println(esameReti);

        System.out.println("\n=== Statistiche ===");
        System.out.println("Totale studenti: " + Studente.getTotaleStudenti());
    }
}

Conclusione

In questo articolo abbiamo introdotto i concetti fondamentali della OOP: classi, oggetti, costruttori, incapsulamento e membri statici.

Nel prossimo articolo approfondiremo ereditarieta, polimorfismo e interfacce: i pilastri avanzati della programmazione a oggetti.

Punti Chiave da Ricordare

  • Classe: Blueprint che definisce attributi e metodi
  • Oggetto: Istanza concreta di una classe
  • Costruttore: Metodo speciale per inizializzare oggetti
  • Incapsulamento: Nascondi i dati, esponi metodi controllati
  • this: Riferimento all'oggetto corrente
  • static: Appartiene alla classe, non alle istanze

Domande frequenti

Cos'è la Programmazione Orientata agli Oggetti (OOP)?

La Programmazione Orientata agli Oggetti è un paradigma che modella il software come una collezione di oggetti che interagiscono tra loro.

Quali sono le caratteristiche principali degli oggetti in OOP?

Gli oggetti rappresentano un'entità del mondo reale con stato (attributi) e comportamento (metodi).

Cosa è il costruttore in OOP?

Il costruttore è un metodo speciale chiamato quando si crea un oggetto, che permette di inizializzare l'oggetto.

Qual è lo scopo dell'incapsulamento in OOP?

L'incapsulamento protegge i dati di un oggetto nascondendoli dall'esterno e fornendo metodi controllati per accedervi.

Fonti e approfondimenti

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti